喜悦国际村 专业PHP开发者社区's Archiver

smcz 发表于 2010-3-8 03:47 PM

iPhone/Mac Objective-C内存管理教程和原理剖析

[align=left][font=宋体]版权声明[/font][/align][align=left][font=宋体]此文版权归作者[/font]Vince Yuan (vince.yuan#gmail.com)[font=宋体]所有。欢迎非营利性转载,转载时必须包含原始链接[/font][url=http://vinceyuan.cnblogs.com/]http://vinceyuan.cnblogs.com/[/url][font=宋体],且必须包含此版权声明的完整内容。[/font][/align][align=left][align=left][font=宋体]版本[/font][font=Calibri] 1.0  [/font][font=宋体]发表于[/font][font=Calibri]2010-03-08[/font][/align][/align][align=left][font=宋体]前言[/font][/align][align=left][font=宋体]初学[/font]objectice-C[font=宋体]的朋友都有一个困惑,总觉得对[/font]objective-C[font=宋体]的内存管理机制琢磨不透,程序经常内存泄漏或莫名其妙的崩溃。我在这里总结了自己对[/font]objective-C[font=宋体]内存管理机制的研究成果和经验,写了这么一个由浅入深的教程。希望对大家有所帮助,也欢迎大家一起探讨。[/font][/align]
[align=left][font=宋体]此文涉及的内存管理是针对于继承于[/font]NSObject[font=宋体]的[/font]Class[font=宋体]。[/font][/align][font=宋体]一[/font] [font=宋体]基本原理[/font]
Objective-C[font=宋体]的内存管理机制与[/font].Net/Java[font=宋体]那种全自动的垃圾回收机制是不同的,它本质上还是[/font]C[font=宋体]语言中的手动管理方式,只不过稍微加了一些自动方法。[/font]
1
Objective-C[font=宋体]的对象生成于堆之上,生成之后,需要一个指针来指向它。[/font]
ClassA *obj1 = [[ClassA alloc] init];

2
Objective-C[font=宋体]的对象在使用完成之后不会自动销毁,需要执行[/font]dealloc[font=宋体]来释放空间(销毁),否则内存泄露。[/font]
[obj1 dealloc];

[font=宋体]这带来了一个问题。下面代码中[/font]obj2[font=宋体]是否需要调用[/font]dealloc[font=宋体]?[/font]
ClassA *obj1 = [[ClassA alloc] init];
ClassA *obj2 = obj1;
[obj1 hello]; //[font=宋体]输出[/font]hello
[obj1 dealloc];
[obj2 hello]; //[font=宋体]能够执行这一行和下一行吗?[/font]
[obj2 dealloc];

[font=宋体]不能,因为[/font]obj1[font=宋体]和[/font]obj2[font=宋体]只是指针,它们指向同一个对象,[/font][obj1 dealloc][font=宋体]已经销毁这个对象了,不能再调用[/font][obj2 hello][font=宋体]和[/font][obj2 dealloc][font=宋体]。[/font]obj2[font=宋体]实际上是个无效指针。[/font]

[font=宋体]如何避免无效指针?请看下一条。[/font]

3
Objective-C[font=宋体]采用了引用计数[/font](ref count[font=宋体]或者[/font]retain count)[font=宋体]。对象的内部保存一个数字,表示被引用的次数。例如,某个对象被两个指针所指向(引用)那么它的[/font]retain count[font=宋体]为[/font]2[font=宋体]。需要销毁对象的时候,不直接调用[/font]dealloc[font=宋体],而是调用[/font]release[font=宋体]。[/font]release[font=宋体]会让[/font]retain count[font=宋体]减[/font]1[font=宋体],只有[/font]retain count[font=宋体]等于[/font]0[font=宋体],系统才会调用[/font]dealloc[font=宋体]真正销毁这个对象。[/font]
ClassA *obj1 = [[ClassA alloc] init]; //[font=宋体]对象生成时,[/font]retain count = 1
[obj1 release]; //release[font=宋体]使[/font]retain count[font=宋体]减[/font]1[font=宋体],[/font]retain count = 0[font=宋体],[/font]dealloc[font=宋体]自动被调用[/font],[font=宋体]对象被销毁[/font]
[font=宋体]我们回头看看刚刚那个无效指针的问题,把[/font]dealloc[font=宋体]改成[/font]release[font=宋体]解决了吗?[/font]
ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1
ClassA *obj2 = obj1; //retain count = 1
[obj1 hello]; //[font=宋体]输出[/font]hello
[obj1 release]; //retain count = 0[font=宋体],对象被销毁[/font]
[obj2 hello];
[obj2 release];
         [obj1 release][font=宋体]之后,[/font]obj2[font=宋体]依然是个无效指针。问题依然没有解决。解决方法见下一条。[/font]

4
Objective-C[font=宋体]指针赋值时,[/font]retain count[font=宋体]不会自动增加,需要手动[/font]retain[font=宋体]。[/font]
ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1
ClassA *obj2 = obj1; //retain count = 1
[color=red][obj2 retain]; //retain count = 2[/color]
[obj1 hello]; //[font=宋体]输出[/font]hello
[obj1 release]; //retain count = 2 – 1 = 1
[obj2 hello]; //[font=宋体]输出[/font]hello
[obj2 release]; //retain count = 0[font=宋体],对象被销毁[/font]
[font=宋体]问题解决!注意,如果没有调用[/font][obj2 release][font=宋体],这个对象的[/font]retain count[font=宋体]始终为[/font]1[font=宋体],不会被销毁,内存泄露。[/font](1-4[font=宋体]可以参考附件中的示例程序[/font]memman-no-pool.m)
[font=宋体]这样的确不会内存泄露,但似乎有点麻烦,有没有简单点的方法?见下一条。[/font]

5
Objective-C[font=宋体]中引入了[/font]autorelease pool[font=宋体](自动释放对象池),在遵守一些规则的情况下,可以自动释放对象。([/font]autorelease pool[font=宋体]依然不是[/font].Net/Java[font=宋体]那种全自动的垃圾回收机制)[/font]
5.1
[font=宋体]新生成的对象,只要调用[/font]autorelease[font=宋体]就行了,无需再调用[/font]release[font=宋体]![/font]
ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1 [font=宋体]但无需调用[/font]release

5.2
[font=宋体]对于存在指针赋值的情况,代码与前面类似。[/font]
ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1
ClassA *obj2 = obj1; //retain count = 1
[color=red][obj2 retain]; //retain count = 2[/color]
[obj1 hello]; //[font=宋体]输出[/font]hello
//[font=宋体]对于[/font]obj1[font=宋体],无需调用(实际上不能调用)[/font]release
[obj2 hello]; //[font=宋体]输出[/font]hello
[obj2 release]; //retain count = 2-1 = 1

[font=宋体]细心的读者肯定能发现这个对象没有被销毁,何时销毁呢?谁去销毁它?(可以参考附件中的示例程序[/font]memman-with-pool.m[font=宋体])请看下一条。[/font]

6
autorelease pool[font=宋体]原理剖析。(其实很简单的,一定要坚持看下去,否则还是不能理解[/font]Objective-C[font=宋体]的内存管理机制。)[/font]
6.1
autorelease pool[font=宋体]不是天生的,需要手动创立。只不过在新建一个[/font]iphone[font=宋体]项目时,[/font]xcode[font=宋体]会自动帮你写好。[/font]autorelease pool[font=宋体]的真名是[/font]NSAutoreleasePool[font=宋体]。[/font]
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
6.2
NSAutoreleasePool[font=宋体]内部包含一个数组([/font]NSMutableArray[font=宋体]),用来保存声明为[/font]autorelease[font=宋体]的所有对象。如果一个对象声明为[/font]autorelease[font=宋体],系统所做的工作就是把这个对象加入到这个数组中去。[/font]
ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1[font=宋体],把此对象加入[/font]autorelease pool[font=宋体]中[/font]
6.3
NSAutoreleasePool[font=宋体]自身在销毁的时候,会遍历一遍这个数组,[/font]release[font=宋体]数组中的每个成员。如果此时数组中成员的[/font]retain count[font=宋体]为[/font]1[font=宋体],那么[/font]release[font=宋体]之后,[/font]retain count[font=宋体]为[/font]0[font=宋体],对象正式被销毁。如果此时数组中成员的[/font]retain count[font=宋体]大于[/font]1[font=宋体],那么[/font]release[font=宋体]之后,[/font]retain count[font=宋体]大于[/font]0[font=宋体],此对象依然没有被销毁,内存泄露。[/font]
6.4
[font=宋体]默认只有一个[/font]autorelease pool[font=宋体],通常类似于下面这个例子。[/font]
int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];

// do something

[pool release];
return (0);
} // main
[font=宋体]所有标记为[/font]autorelease[font=宋体]的对象都只有在程序退出时([/font]pool[font=宋体]销毁时)才被销毁。如果你有大量的对象标记为[/font]autorelease[font=宋体],这显然不能很好的利用内存,在[/font]iphone[font=宋体]这种内存受限的程序中是很容易造成内存不足的。例如:[/font]
int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i, j;
for (i = 0; i < 100; i++ )
{
for (j = 0; j < 100000; j++ )
    [NSString stringWithFormat:@"1234567890"];//[font=宋体]产生的对象是[/font]autorelease[font=宋体]的。[/font]
}
[pool release];
return (0);
} // main
[font=宋体](可以参考附件中的示例程序[/font]memman-many-objs-one-pool.m[font=宋体],运行时通过监控工具可以发现使用的内存在急剧增加,直到[/font]pool[font=宋体]销毁时才被释放)你需要考虑下一条。[/font]

7
Objective-C[font=宋体]程序中可以嵌套创建多个[/font]autorelease pool[font=宋体]。在需要大量创建局部变量的时候,可以创建内嵌的[/font]autorelease pool[font=宋体]来及时释放内存。[/font]
int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int i, j;
for (i = 0; i < 100; i++ )
{
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
for (j = 0; j < 100000; j++ )
    [NSString stringWithFormat:@"1234567890"];//[font=宋体]产生的对象是[/font]autorelease[font=宋体]的。[/font]
[loopPool release];
}
[pool release];
return (0);
} // main
[font=宋体](可以参考附件中的示例程序[/font]memman-many-objs-many-pools.m[font=宋体],占用内存的变化极小)[/font]

[font=宋体]示例代码文件链接:[/font][url=http://files.cnblogs.com/VinceYuan/objective-c-memman.zip][font=Calibri]http://files.cnblogs.com/VinceYuan/objective-c-memman.zip[/font][/url]


[font=宋体]二[/font][font=Calibri] [/font][font=宋体]口诀与范式[/font]
[font=Calibri]1[/font]
[font=宋体]口诀。[/font]
[font=Calibri]1.1[/font]
[font=宋体]谁创建,谁释放(类似于“谁污染,谁治理”)。如果你通过[/font][font=Calibri]alloc[/font][font=宋体]、[/font][font=Calibri]new[/font][font=宋体]或[/font][font=Calibri]copy[/font][font=宋体]来创建一个对象,那么你必须调用[/font][font=Calibri]release[/font][font=宋体]或[/font][font=Calibri]autorelease[/font][font=宋体]。换句话说,不是你创建的,就不用你去释放。[/font]
[font=宋体]例如,你在一个函数中[/font][font=Calibri]alloc[/font][font=宋体]生成了一个对象,且这个对象只在这个函数中被使用,那么你必须在这个函数中调用[/font][font=Calibri]release[/font][font=宋体]或[/font][font=Calibri]autorelease[/font][font=宋体]。如果你在一个[/font][font=Calibri]class[/font][font=宋体]的某个方法中[/font][font=Calibri]alloc[/font][font=宋体]一个成员对象,且没有调用[/font][font=Calibri]autorelease[/font][font=宋体],那么你需要在这个类的[/font][font=Calibri]dealloc[/font][font=宋体]方法中调用[/font][font=Calibri]release[/font][font=宋体];如果调用了[/font][font=Calibri]autorelease[/font][font=宋体],那么在[/font][font=Calibri]dealloc[/font][font=宋体]方法中什么都不需要做。[/font]
[font=Calibri]1.2[/font]
[font=宋体]除了[/font][font=Calibri]alloc[/font][font=宋体]、[/font][font=Calibri]new[/font][font=宋体]或[/font][font=Calibri]copy[/font][font=宋体]之外的方法创建的对象都被声明了[/font][font=Calibri]autorelease[/font][font=宋体]。[/font]
[font=Calibri]1.3[/font]
[font=宋体]谁[/font][font=Calibri]retain[/font][font=宋体],谁[/font][font=Calibri]release[/font][font=宋体]。只要你调用了[/font][font=Calibri]retain[/font][font=宋体],无论这个对象是如何生成的,你都要调用[/font][font=Calibri]release[/font][font=宋体]。有时候你的代码中明明没有[/font][font=Calibri]retain[/font][font=宋体],可是系统会在默认实现中加入[/font][font=Calibri]retain[/font][font=宋体]。不知道为什么苹果公司的文档没有强调这个非常重要的一点,请参考范式[/font][font=Calibri]2.7[/font][font=宋体]和第三章。[/font]
[font=Calibri]2[/font]
[font=宋体]范式。[/font]
[font=宋体]范式就是模板,就是依葫芦画瓢。由于不同人有不同的理解和习惯,我总结的范式不一定适合所有人,但我能保证照着这样做不会出问题。[/font]
[font=Calibri]2.1[/font]
[font=宋体]创建一个对象。[/font]
[font=Calibri]ClassA *obj1 = [[ClassA alloc] init];[/font]
[font=Calibri]2.2[/font]
[font=宋体]创建一个[/font][font=Calibri]autorelease[/font][font=宋体]的对象。[/font]
[font=Calibri]ClassA *obj1 = [[[ClassA alloc] init] autorelease];[/font]
[font=Calibri]2.3[/font]
[font=Calibri]Release[/font][font=宋体]一个对象后,立即把指针清空。(顺便说一句,[/font][font=Calibri]release[/font][font=宋体]一个空指针是合法的,但不会发生任何事情)[/font]
[font=Calibri][obj1 release];[/font]
[font=Calibri]obj1 = nil;[/font]
[font=Calibri]2.4[/font]
[font=宋体]指针赋值给另一个指针。[/font]
[font=Calibri]ClassA *obj2 = obj1;[/font]
[font=Calibri][obj2 retain];[/font]
[font=Calibri]//do something[/font]
[font=Calibri][obj2 release];[/font]
[font=Calibri]obj2 = nil;[/font]
[font=Calibri]2.5[/font]
[font=宋体]在一个函数中创建并返回对象,需要把这个对象设置为[/font][font=Calibri]autorelease[/font]
[font=Calibri]ClassA *Func1()[/font]
[font=Calibri]{[/font]
[font=Calibri]
ClassA *obj = [[[ClassA alloc]init]autorelease];[/font]
[font=Calibri]
return obj;[/font]
[font=Calibri]}[/font]
[font=Calibri]2.6[/font]
[font=宋体]在子类的[/font][font=Calibri]dealloc[/font][font=宋体]方法中调用基类的[/font][font=Calibri]dealloc[/font][font=宋体]方法[/font]
[align=left][align=left][font=Calibri]-(void) dealloc[/font][/align][/align][align=left][align=left][font=Calibri]{[/font][/align][/align][align=left][align=left][font=Calibri]
…[/font][/align][/align][align=left][align=left][font=Calibri]
[super dealloc];[/font][/align][/align][font=Calibri]}[/font]
[font=Calibri]2.7[/font]
[font=宋体]在一个[/font][font=Calibri]class[/font][font=宋体]中创建和使用[/font][font=Calibri]property[/font][font=宋体]。[/font]
[font=Calibri]2.7.1[/font]
[font=宋体]声明一个成员变量。[/font]
[font=Calibri]ClassB *objB;[/font]
[font=Calibri]2.7.2[/font]
[font=宋体]声明[/font][font=Calibri]property[/font][font=宋体],加上[/font][font=Calibri]retain[/font][font=宋体]参数。[/font]
[font=Calibri]@property (retain) ClassB* objB;[/font]
[font=Calibri]2.7.3[/font]
[font=宋体]定义[/font][font=Calibri]property[/font][font=宋体]。([/font][font=Calibri]property[/font][font=宋体]的默认实现请看第三章)[/font]
[font=Calibri]@synthesize objB;[/font]
[font=Calibri]2.7.4[/font]
[font=宋体]除了[/font][font=Calibri]dealloc[/font][font=宋体]方法以外,始终用[/font][font=Calibri].[/font][font=宋体]操作符的方式来调用[/font][font=Calibri]property[/font][font=宋体]。[/font]
[font=Calibri]self.objB [/font][font=宋体]或者[/font][font=Calibri]objA.objB[/font]
[font=Calibri]2.7.5[/font]
[font=宋体]在[/font][font=Calibri]dealloc[/font][font=宋体]方法中[/font][font=Calibri]release[/font][font=宋体]这个成员变量。[/font]
[font=Calibri][objB release];[/font]
[font=宋体]示例代码如下(详细代码请参考附件中的[/font][font=Calibri]memman-property.m[/font][font=宋体],你需要特别留意对象是在何时被销毁的。):[/font]
[align=left][align=left][font=Calibri]@interface ClassA : NSObject[/font][/align][/align][align=left][align=left][font=Calibri]{[/font][/align][/align][align=left][align=left][font=Calibri]
ClassB* objB;[/font][/align][/align][align=left][align=left][font=Calibri]}[/font][/align][/align][align=left][align=left][font=Calibri] [/font][/align][/align][align=left][align=left][font=Calibri]@property (retain) ClassB* objB;[/font][/align][/align][align=left][align=left][font=Calibri]@end[/font][/align][/align][align=left][align=left][font=Calibri] [/font][/align][/align][align=left][align=left][font=Calibri]@implementation ClassA[/font][/align][/align][align=left][align=left][font=Calibri]@synthesize objB;[/font][/align][/align][align=left][align=left][font=Calibri]-(void) dealloc[/font][/align][/align][align=left][align=left][font=Calibri]{[/font][/align][/align][align=left][align=left][font=Calibri]
[objB release];[/font][/align][/align][align=left][align=left][font=Calibri]
[super dealloc];[/font][/align][/align][align=left][align=left][font=Calibri]}[/font][/align][/align][align=left][align=left][font=Calibri]@end[/font][/align][/align][align=left][align=left][font=Calibri]2.7.6[/font]
[font=宋体]给这个[/font][font=Calibri]property[/font][font=宋体]赋值时,有手动[/font][font=Calibri]release[/font][font=宋体]和[/font][font=Calibri]autorelease[/font][font=宋体]两种方式。[/font][/align][/align][align=left][align=left][font=Calibri]void funcNoAutorelease()[/font][/align][/align][align=left][align=left][font=Calibri]{[/font][/align][/align][align=left][align=left][font=Calibri]
ClassB *objB1 = [[ClassB alloc]init];[/font][/align][/align][align=left][align=left][font=Calibri]
ClassA *objA = [[ClassA alloc]init];[/font][/align][/align][align=left][align=left][font=Calibri]
objA.objB = objB1;[/font][/align][/align][align=left][align=left][font=Calibri]
[objB1 release];[/font][/align][/align][align=left][align=left][font=Calibri]
[objA release];[/font][/align][/align][align=left][align=left][font=Calibri]}[/font][/align][/align][align=left][align=left][font=Calibri] [/font][/align][/align][align=left][align=left][font=Calibri]void funcAutorelease()[/font][/align][/align][align=left][align=left][font=Calibri]{[/font][/align][/align][align=left][align=left][font=Calibri]
ClassB *objB1 = [[[ClassB alloc]init] autorelease];[/font][/align][/align][align=left][align=left][font=Calibri]
ClassA *objA = [[[ClassA alloc]init] autorelease];[/font][/align][/align][align=left][align=left][font=Calibri]
objA.objB = objB1;[/font][/align][/align][font=Calibri]}[/font]


[font=宋体]示例代码文件链接:[/font][url=http://files.cnblogs.com/VinceYuan/objective-c-memman.zip][font=Calibri]http://files.cnblogs.com/VinceYuan/objective-c-memman.zip[/font][/url]




[font=宋体]三[/font][font=Calibri] @property (retain)[/font][font=宋体]和[/font][font=Calibri]@synthesize[/font][font=宋体]的默认实现[/font]
[font=宋体]在这里解释一下[/font][font=Calibri]@property (retain) ClassB* objB;[/font][font=宋体]和[/font][font=Calibri]@synthesize objB;[/font][font=宋体]背后到底发生了什么[/font][font=Calibri](retain property[/font][font=宋体]的默认实现[/font][font=Calibri])[/font][font=宋体]。[/font][font=Calibri]property[/font][font=宋体]实际上是[/font][font=Calibri]getter[/font][font=宋体]和[/font][font=Calibri]setter[/font][font=宋体],针对有[/font][font=Calibri]retain[/font][font=宋体]参数的[/font][font=Calibri]property[/font][font=宋体],背后的实现如下(请参考附件中的[/font][font=Calibri]memman-getter-setter.m[/font][font=宋体],你会发现,结果和[/font][font=Calibri]memman-property.m[/font][font=宋体]一样):[/font]
[align=left][align=left][font=Calibri]@interface ClassA : NSObject[/font][/align][/align][align=left][align=left][font=Calibri]{[/font][/align][/align][align=left][align=left][font=Calibri]
ClassB *objB;[/font][/align][/align][align=left][align=left][font=Calibri]}[/font][/align][/align][align=left][align=left][font=Calibri] [/font][/align][/align][align=left][align=left][font=Calibri]-(ClassB *) getObjB;[/font][/align][/align][align=left][align=left][font=Calibri]-(void) setObjB:(ClassB *) value;[/font][/align][/align][align=left][align=left][font=Calibri]@end[/font][/align][/align][align=left][align=left][font=Calibri] [/font][/align][/align][align=left][align=left][font=Calibri]@implementation ClassA[/font][/align][/align][align=left][align=left][font=Calibri]-(ClassB*) getObjB[/font][/align][/align][align=left][align=left][font=Calibri]{[/font][/align][/align][align=left][align=left][font=Calibri]
return objB;[/font][/align][/align][align=left][align=left][font=Calibri]}[/font][/align][/align][align=left][align=left][font=Calibri] [/font][/align][/align][align=left][align=left][font=Calibri]-(void) setObjB:(ClassB*) value[/font][/align][/align][align=left][align=left][font=Calibri]{[/font][/align][/align][align=left][align=left][font=Calibri]
if (objB != value)[/font][/align][/align][align=left][align=left][font=Calibri]
{[/font][/align][/align][align=left][align=left][font=Calibri]
[objB release];[/font][/align][/align][align=left][align=left][font=Calibri]
objB = [value retain];[/font][/align][/align][align=left][align=left][font=Calibri]
}[/font][/align][/align][align=left][align=left][font=Calibri]}[/font][/align][/align][align=left][align=left][font=宋体]在[/font][font=Calibri]setObjB[/font][font=宋体]中,如果新设定的值和原值不同的话,必须要把原值对象[/font][font=Calibri]release[/font][font=宋体]一次,这样才能保证[/font][font=Calibri]retain count[/font][font=宋体]是正确的。[/font][/align][/align][align=left][align=left][font=宋体]由于我们在[/font][font=Calibri]class[/font][font=宋体]内部[/font][font=Calibri]retain[/font][font=宋体]了一次(虽然是默认实现的),所以我们要在[/font][font=Calibri]dealloc[/font][font=宋体]方法中[/font][font=Calibri]release[/font][font=宋体]这个成员变量。[/font][/align][/align][align=left][align=left][font=Calibri]-(void) dealloc[/font][/align][/align][align=left][align=left][font=Calibri]{[/font][/align][/align][align=left][align=left][font=Calibri]
[objB release];[/font][/align][/align][align=left][align=left][font=Calibri]
[super dealloc];[/font][/align][/align][align=left][align=left][font=Calibri]}[/font][/align][/align][font=Calibri] [/font]
[font=宋体]补充说明[/font]
[font=宋体]在研究[/font][font=Calibri]retain count[/font][font=宋体]的时候,我不建议用[/font][font=Calibri]NSString[/font][font=宋体]。因为在下面的语句中,[/font]
[font=Calibri]NSString *str1 = @”constant string”;[/font]
[font=Calibri]str1[/font][font=宋体]的[/font][font=Calibri]retain count[/font][font=宋体]是个很大的数字。[/font][font=Calibri]Objective-C[/font][font=宋体]对常量字符串做了特殊处理。[/font]
[font=宋体]当然,如果你这样创建[/font][font=Calibri]NSString[/font][font=宋体],得到的[/font][font=Calibri]retain count[/font][font=宋体]依然为[/font][font=Calibri]1[/font]
[font=Calibri]NSString *str2 = [NSString stringWithFormat:@”123”];[/font]
[font=Calibri] [/font]

[font=宋体]示例代码文件链接:[/font][url=http://files.cnblogs.com/VinceYuan/objective-c-memman.zip][font=Calibri]http://files.cnblogs.com/VinceYuan/objective-c-memman.zip[/font][/url]

页: [1]

Powered by Discuz! Archiver 7.0.0  © 2001-2009 Comsenz Inc.