博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Object-C内存管理---引用计数与字符串

Posted on 2012-04-05 21:47  三块石头  阅读(732)  评论(0)    收藏  举报
// 字符串引用计数
#import <Foundation/Foundation.h>

int main (int argc, char *argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

NSString *myStr1 = @"Constant string";

NSString *myStr2 = [NSString stringWithString: @"string 2"];
NSMutableString *myStr3 = [NSMutableString stringWithString: @"string 3"];
NSMutableArray *myArr = [NSMutableArray array];
NSLog (@"Retain count: myStr1: %lx, myStr2: %lx, myStr3: %lx",
(unsigned long) [myStr1 retainCount],

(unsigned long) [myStr2 retainCount],

(unsigned long) [myStr3 retainCount]);
[myArr addObject: myStr1];
[myArr addObject: myStr2];
[myArr addObject: myStr3];
NSLog (@"Retain count: myStr1: %lx, myStr2: %lx, myStr3: %lx",
(unsigned long) [myStr1 retainCount],

(unsigned long) [myStr2 retainCount],

(unsigned long) [myStr3 retainCount]);
[myStr1 retain];
[myStr2 retain];
[myStr3 retain];
NSLog (@"Retain count: myStr1: %lx, myStr2: %lx, myStr3: %lx",
(unsigned long) [myStr1 retainCount],

(unsigned long) [myStr2 retainCount],

(unsigned long) [myStr3 retainCount]);
// Bring the reference count of myStr3 back down
[myStr3 release];

[pool drain];
return 0;
}

程序输出:

Retain count: myStr1: fffffffffffffff, myStr2: fffffffffffffff, myStr3: 1 
Retain count: myStr1: fffffffffffffff, myStr2: fffffffffffffff, myStr3: 2
Retain count: myStr1: fffffffffffffff, myStr2: fffffffffffffff, myStr3: 3

  NSString对象myStr1被赋值为字符串常量@”Constant string”.常量字符串和其他对象申请的内存空间有所不同。由于常量字符串不可改变,所以它不需引用计数,这也是为什么myStr1的retainCount为0xfffffffffffffff的原因。从myStr2的retainCount也可以看出来. 以常量字符串初始化的不可变字符串的retainCount也是没什么意义的.

  注意:这里系统比较智能,它探测到了那个不可变字符串是以常量字符串初始化的,在Mac Leopard之前的版本,编译器不会做优化,所以myStr2依然会有一个正常的retainCount[1].  

  变量myStr3被赋值为常量字符串@”string3”的副本,因为myStr3是一个NSMutableString对象,这意味着它的内存随时可能会发生改变。因为常量字符串的内容是不可变的,所以不能像myStr2那样,直接将指针指向字符串@”string 3”的内存地址。

  所以,mystr3就有了一个有效的引用计数了,这点从程序输出中可以看出。从最后的两个NSLog输出中也可以看出,将对象加入数组或者调用retain方法都会改变对象的引用计数。同时,Foundation的stringWithString方法也会将对象放入资源自动释放池中;Foundation的array方法也会将myAttr放入资源自动释放池。

  在资源自动释放池释放之前,myStr3被释放了一次,此时myStr3的引用计数减为2,当资源自动释放池释放时,会使得myStr3引用计数减到0使得myStr3被销毁。为什么这么说呢?资源自动释放池释放时,其内的任何一个对象(这些对象都调用过autorelease方法)都会自动调用各自的release方法。字符串对象myStr3通过stringWithString方法创建,它会增加到资源自动释放池中,所以它会自动调用release方法,这样它的引用计数变为1;当资源自动释放池的数组释放时,在数组里面的每个元素都会调用release方法—myStr3也不例外,这样myStr3的引用计数就减为0了,最后myStr3会被销毁。

  你必须小心的释放对象,否则会导致过度释放对象.在上面的程序中,如果在资源池释放之前将myStr3的引用计数减为小于2,程序将得到非法的引用指针,这样会导致程序异常退出,出现段错误,也就是经典的EXC_BAD_ACCESS。



[1]译者注: 在笔者的Lion Xcode4下,myStr2的retainCount为1