ARC
1、ARC
是Automatic Reference Counting
(自动引用计数器)的简称。
ARC是ios5.0引入的新特性,完全消除手动管理内存的繁琐,编译器会自动在适合的代码里面插入适当的retain,release,autorelease的语句。我们不要再担心内存管理,因为编译器帮我们做了这一切。
ARC是编译器的特性,并非运行时的特性
2、基本原理
ARC的规则就是只要对象没有强指针引用,就会被释放掉,换而言之 只要还有一个强引用指针变量指向对象,那么这个对象就会存在内存中。弱指针指向的对象,会被自动变成空指针(nil指针),从而不会引发野指针错误。
AutoreleasePool
参考:
https://www.jianshu.com/p/b75a99892261
自动释放池存储于内存中的栈并遵循"先进后出"原则,因为它是将数据存储在栈的容器中。因此就出现先进后出原则
1、介绍
autoReleasePool和ARC都是iOS5.0出来的,AutoreleasePool(自动释放池)是OC中的内存自动回收机制,它可以延迟自动释放池中变量release的时机。在正常情况下,创建的变量会在超出其作用域的时候release,但是如果将变量加入AutoreleasePool,那么release将延迟执行。
2、ARC下
使用场景
苹果官方给的建议之一是 循环中包含了大量临时创建的对象。
除此之外,当函数写的很长,在中间出现很多变量,占据大量内存也可以使用
ARC下用 @autoreleasepool {}主要还是为了避免内存峰值。
正常情况下,你创建的变量会在超出其作用域的时候被释放掉。
而如果你的函数写的很长,在你函数运行过程中出现很多中间变量,占据了大量的内存,怎么办?
用@autoreleasepool。在@autoreleasepool中创建的变量,会在@autoreleasepool结束的时候执行一次release,进行释放。其实@autoreleasepool就相当于一层作用域。
3、autorelease
的优化
1)优化内存,在for循环创建的时候,使用@autoreleasepool 包起来,让每次循环结束时,可以及时释放临时对象的内存
4、解释
@autoReleasePool什么时间释放? 每次Runloop结束时会有专门的时机用来释放
5、用法
@autoreleasepool {
// code do something, creates some autoreleases objects
}
6、autorelease
使用注意:
1.占用内存大的对象不要随便使用autorelease,担心对象释放的时间太迟
2.占用内存小的对象使用autorelease,没有太大影响
autoreleasepool:在iOS程序运行时,会创建无数个池子,这些池子以栈结构存在(先进后出);当一个对象调用autorelease方法时,会将这个对象放到栈顶的释放池。
7.堆和栈的区别:
.text段 : 存放代码
.data区 : 存放全局变量
堆区 : 存放对象,需要程序员手动释放
栈区 : 存放局部变量 ,程序自动管理内存
8.引用计数器
- 用来表示对象被引用的次数,当为0时,会被回收,新对象被创建时,默认为1
- retain +1, release -1, retainCount查看
- 当对象的的引用计数器为0时,它将被销毁,系统会向对象发送一条dealloc消息,dealloc就像对象的遗言,要重写dealloc方法,并且在调用[super dealloc]方法时,一定要放在最后
当使用new alloc copy等关键字时,引用计数器会+1
使用release或者autorelease时会-1
9.常见错误
1.僵尸对象:引用计数器为0的对象为僵尸对象
2.野指针:指向僵尸对象的指针 继续释放会崩溃 EXC_BAD_ACCESS(code=1,address=)
3.空指针:没有指向任何东西的指针
4.防止野指针出现常用方法:p=nil
10.循环引用问题的出现:相互retain
解决思路:
1、一段使用retain,另一端使用assign
2、使用assign段中,在dealloc方法中不需要释放对方
11.ARC
1.不允许调用release、retain、retainCount
2.允许重写dealloc,但是不允许调用[super dealloc]
12.ARC
与MRC
混用
1.自己的旧项目没有使用ARC,但是引入的第三方库却是使用了ARC的。
(给采用了ARC的源文件,添加-fobjc-arc选项)
2.自己的新项目使用了ARC,但是引入的第三方库或者以前写的代码却没有使用ARC。
(添加-fno-objc-arc) build Phases找到相应的类,添加-fno-objc-arc
13.使用block时什么情况会发生引用循环,如何解决?
一个对象中强引用了block,在block中又使用了该对象,就会发生循环引用。
解决方法是将该对象使用__weak或者__block修饰符修饰之后再在block中使用
__weak __typeof(&*self)weakSelf = self 调用外部方法
id __block weakSelf = self; 在block内部修改外部变量的值
#define WS(weakSelf) __weak __typeof(&*self)weakSelf = self;
WS(weakSelf)
[self.tableView addHeaderWithCallback:^{
[weakself requestMemberList];
}];
14.Objective-C
如何对内存管理的,说说你的看法和解决方法?
- 每个对象都有一个引用计数器,每个新对象的计数器是1,当对象的计数器减为0时,就会被销毁
2.通过retain可以让对象的计数器+1、release可以让对象的计数器-1
3.还可以通过autorelease pool管理内存
4.如果用ARC,编译器会自动生成管理内存的代码
注意:不管是MRC还是ARC都是在编译时完成的
15.内存管理的几条原则时什么?按照默认法则.哪些方法生成的对象需要手动释放?在和property结合的时候怎样有效的避免内存泄露?
1.只要调用了alloc、copy、new方法产生了一个新对象,都必须在最后调用一次release或者autorelease
2.只要调用了retain,都必须在最后调用一次release或者autorelease
3.@property如果用了copy或者retian,就需要对不再使用的属性做一次release操作
4.如果用了ARC,另外讨论
16.看下面的程序,三次NSLog会输出什么?为什么?
NSMutableArray* ary = [[NSMutableArray array] retain];
NSString *str = [NSString stringWithFormat:@"test"];
[str retain];
[ary addObject:str];
NSLog(@"%ld", (unsigned long)[str retainCount]);
[str retain];
[str release];
[str release];
NSLog(@"%ld", (unsigned long)[str retainCount]);
[ary removeAllObjects];
NSLog(@"%ld", (unsigned long)[str retainCount]);
结果:-1、-1、-1 。-1代表没有引用计数或者引用计数非常大,因为str是字符串,字符串在常量区,没有引用计数。引用计数为-1,这可以理解为NSString实际上是一个字符串常量,是没有引用计数的(或者它的引用计数是一个很大的值(使用%lu可以打印查看),对它做引用计数操作没实质上的影响)
17.写一个setter方法用于完成@property (nonatomic,retain)NSString *name,写一个setter方法用于完成@property(nonatomic,copy)NSString *name.
@property (nonatomic, retain) NSString *name;
- (void)setName:(NSString *)name
{
if (_name != name) {
[_name release];
_name = [name retain];
}
}
2> @property(nonatomic, copy) NSString *name;
- (void)setName:(NSString *)name
{
if (_name != name) {
[_name release];
_name = [name copy];
}
}
18.Objective-C
使用什么机制管理对象内存?
MRC 手动引用计数
ARC 自动引用计数,现在通常 ARC
通过 retainCount 的机制来决定对象是否需要释放。 每次 runloop 的时候,都会检查对象的 retainCount,如果 retainCount 为 0,说明该对象没有地方需要继续使用了,可以释放掉了
19.ARC
下还会存在内存泄露吗?
循环引用会导致内存泄露.
Objective-C 对象与 CoreFoundation 对象进行桥接的时候如果管理不当也会造成内存泄露.
CoreFoundation 中的对象不受 ARC 管理,需要开发者手动释放
20>Objective-C
如何对内存管理的,说说你的看法和解决方法?
答:Objective-C的内存管理主要有三种方式ARC(自动内存计数)、手动内存计数、内存池。
1). 自动内存计数ARC:由Xcode自动在App编译阶段,在代码中添加内存管理代码。
2). 手动内存计数MRC:遵循内存谁申请、谁释放;谁添加,谁释放的原则。
3). 内存释放池Release Pool:把需要释放的内存统一放在一个池子中,当池子被抽干后(drain),池子中所有的内存空间也被自动释放掉。内存池的释放操作分为自动和手动。自动释放受runloop机制影响。