1.内存管理原则(引用计数)
iOS的对象都继承于NSObject, 该对象有一个方法 :retainCount,内存引用计数。引用计数在很多计数都用到:window下的COM组件,多线程的信号量,读写锁,思想都一样。
alloc 对象分配后引用计数为1
retain 对象引用计数+1
copy copy一个对象变成新的对象(新内存地址)引用计数为1原来对象计数不变
release 对象引用计数-1 如果为0释放内存
autorelease 对象引用计数-1 如果为0不马上释放, 最近一个自动释放池释放
可以用以下方法打印引用计数
NSLog (@"a retainCount : %u", [a retainCount])
内存管理的原则就是最终的引用计数要平衡,
如果最后引用计数大于0 则会内存泄露
如果引用计数等于0还对该对象进行操作,则会出现内存访问失败,即crash 所以尽量设置为nil
2.autoReleasePool
每个工程都有一个main.m文件:内容如下:
int main(int argc, char *argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}
很明显C语言的main函数
NSAutoreleasePool是用来做autorelease变量释放的, 前面说了, autorelease不会马上释放, 当他到了最近的pool release 时 会检查retain count 是不是0, 为0就释放
当我们在一段代码时加入大量的autorelease 变量时,我们应该为这段代码加上 AutoreleasePool, 其他时候不用
在返回一个对象时常常像C/C++一样返回一个对象到栈, 只能用autorelease对象
3. 成员变量与属性
实际情况并非上面那么简单, 你可能需要在一个函数里调用另一个函数分配的变量这时候有两个选择: 类成员变量和使用属性
@interface TestMem:NSObject {
TestObject *m_testObject; // 成员变量
TestObject *testObject; // 成员变量
}
成员变量与上面的内存管理师一直的, 只是在不同的函数里要保持引用计数加减的平衡,所以要你要每次分配的时候检查是否上次已经分配了。 是否还能调用什么时候用属性?
1.把成员作为public.
2.outlet一般声明为属性(这个内存于系统控制,但我们还是应该做一样操作, 后面会讲)
3.如果很多函数都需要改变这个对象, 或这个函数会触发很多次, 建议使用属性。我们看看属性函数展开后是什么样子:
-(void)setTestObject:(id)newValue {
testObject = newValue;
}
- (void)setTestObject:(id)newValue {
if (testObject!= newValue) {
[testObject release];
testObject = [newValue retain];
}
}
- (void)setTestObject:(id)newValue {
if (testObject != newValue) {
[testObject release];
testObjce = [newValue copy];
}
}
assign 相当于指针赋值, 不对引用计数进行操作, 注意原对象不用了, 一定要把这个设置为nil
retain 相当于对原对象的引用计数改变,生成一个新对象引用计数为1
注意:
self.testObject 左值调用的是setTestObject 方法。右值为get方法,get方法比较简单不用说了 而真接testObject使用的是成员变量
self.testObject = [[testObject alloc] init]; // 错 retain 两次
testObject = [NSArray objectbyindex:0]; // 错 不安全,没有retain 后面release 会出错
4.自动管理对象
iOS 提供了很多static(+)创建对象的类方法, 这些方面是静态的,可以直接用类名调用如:
NSString *testString = [NSString stringWithFormat: @"test"];
testString 是自动管理对象, 你不用release他, 他有一个很大的 retain count, release后数字不变
5 .例外
有一些通过alloc生成的对象相同是自动管理的如:
NSString *testString = [NSString stringWithFormat:@"test"];
retainCount 同样是很大的数, 没办法release
但为了代码对应, 还是应该加上[testString release];
不然xcode的Analyze 会认识内存leak, 但Instruments leak 工具检测是没有的
IPhone/Mac Objective-C内存管理教程和原理抛析
前言
初学Objective—C的朋友都有一个困惑, 总觉的对Objective-C的内存管理机制琢磨不透,程序经常内存泄露或莫名其妙崩溃。我在这里总结了自己对Object—C内存管理机制的研究成果和经验, 写了这么一个由浅入深的教程。希望对大家有所帮助, 也欢迎大家一起探讨。
一、基本原理
Objective-C的对象在使用完成之后不会自动销毁, 需要执行dealloc来释放空间(销毁), 否则内存泄露。
在此不在详述。
二、口诀与范式
1、口诀。
1.1 谁创建, 谁释放, (类似于“谁无言, 谁治理”)。如果你通过alloc、new或copy来创建一个对象,那么你必须调用release或autorelease。换句话说,不是你创建的,就不用你去释放。
例如, 你在一个函数中alloc生成了一个对象, 且这个对象只在这个函数中被使用,那么你必须在这个函数中调用release或者autorelease。如果你在一个class的某个方法中alloc一个成员对象, 且没有调用autorelease那么你需要在这个类的dealloc方法中调用release;如果调用了autorelease, 那么在dealloc方法中什么都不需要做。
1.2 除了alloc、new或copy之外的方法创建的对象都被声明了autorelease
1.3 谁retain, 谁release 。只要你调用了retain, 无论这个对象时如何生成的,你都要调用release。 有时候你的代码中明明没有retain,可是系统会在默认实现中加入retain。不知道为什么苹果公司的文档没有强调这个非常重要的一点
2. 范式
范式就是模板, 几十照葫芦画瓢。 由于不同人有不同的理解和习惯, 我总结的范式不一定适合所有人, 但我能保证照着这样做不会出问题
2.1 创建一个对象
ClassA *objc1 = [[ClassA class] init];
2.2 创建一个autorelease的对象
ClassA *obj1 = [[[ClassA alloc] init] autorelease];
2.3 Release一个对象后, 立即把指针清空。
[objc1 release];
obj1 = nil
三、系统自动创建新的autorelease pool
在生成新的Run Loop的时候, 系统会自动创建新的autorelease pool 。注意。此处不同于Xcode在新建项目时自动生成的代码中加入的autorelease pool。 Xcode 生成的代码可以被删除, 但是系统自动创建的新的autorelease pool是无法删除的(对于无Garbage Collection 的环境来说)。 Objective-C没有给出实现代码,官方文档也没有说明。
网友评论