内存管理 reference count

原创 2007年09月23日 12:29:00
 

HTML Tags and JavaScript tutorial



内存管理 reference count




reference count  (引用计数)的概念其实很简单, 就是每个对象都有一个reference count 用来表明有多少其他的对象目前正保留一个对它的引用(reference).  对象A 想要引用对象B, A 就把B 的 reference count 加 1。 当A 结束了对B 的引用, A 就把 B 的reference count 减 1.   当没有任何对象再引用 B 时, B 的 reference count
就减为0, B 就被清除(deallocated), 内存就被释放。清除B的时候, 被B所用的对象的 reference count 也可能减小, 也可能使它们被清除。
reference count  (引用计数)是 NSObject 和 NSAutoreleasePool 两个类提供的机制。引用计数不是自动的, 编译器无法决定一个对象的生命周期,所以必须手动调用以下方法来控制 引用计数.





 NSObject

-retain

reference count 增 1。



 NSObject

-release

reference count 减一。



 NSAutoreleasePool

-autorelease

在将来的某时reference count 减一。



 NSObject

-alloc

为一个对象分配内存,并返回这个对象,reference count 为1。



 NSObject

-copy

生成一个对象的拷贝,并返回此对象, reference count 为 1。






发送+alloc 或者 +allocWithZone: 消息给类, 就会预留出内存给一个新的实例, reference count 为 1。 通过 retain ,  其他对象可以引用这个类实例。




[object retain];
同样
[object release];
减少reference count至零时,对象立即被清除, 此时,为了防止错误的发送消息给一个不存在的对象, 我们最好重新设置对象的引用, 通常使用 nil:
object = nil;
获取reference count 的值, 需要发送 retainCount 消息给对象。 这对调试程序有用。


release 规则:


总之,
以下每个方法必须有一个 -release 对应:
+alloc
+allocWithZone
-copy
-mutableCopy
-copyWithZone
-mutableCopyWithZone
-retain



特殊情况

有时, reference count 不这磨简单。 当需要返回一个对象的引用时, 下面这个方法是错误的:
- (NSObject *) incorrectMethod1
{
NSObject *result = [[NSObject alloc] init];
return result;
}
错误是:
没有相对应 alloc 消息的 -release .
记住 :新的NSObject 实例生成时,reference count 为1, 并且实例被返回,但如果这个实例返回后不被使用, 那末就出现了内存泄露。
另一个错误的方法:
-(NSObject *) incorrectMethod2
{
    NSObject *result = [[ NSObject alloc] init];
    [result release];
    return result;
}
错误:
虽然参照规则, 使用了- release 去对应 +alloc , 但是发送了 -release 消息之后, result 就被清除了,而程序倚赖返回的result reference , 因此程序就可能崩溃了,
因为返回的reference 指向了一个早已被清除了的对象。
那末如何解决这个问题呢,既不会发生内存泄露或者返回一个无效的对象reference?答案就是使用 release pool   (释放池) 。 一个临时存放对象的地方, 当一个对象被加入释放池中, 这个对象就注册了 - 稍候一定会接收到一个 -release  的消息。当另一个对象想要保留一个被调用对象的reference,  就会发送一个- retain 消息给那个要使用的对象。在未来某个时候,释放池会被清除,同时池内所有的对象被释放。池内任何对象的reference count 为零时, 这些对象就被清除。
来看两个情况:
情况1。




step

动作

retain count



1

对象被分配内存, (allocated)

1



2

对象被加入释放池

1



3

对象由方法返回

1



4

对象被其他调用者 retain 住。

2



5

释放池被清除(deallocated), 对象被释放。

1



 

 

 




  由于对象的retain count 是1,所以调用对象必须最终释放被条用的对象,否则会发生内存泄露。
情况2:




 

 

retain count



1

对象被分配内存,

1



2

对象被加入释放池

1



3

对象由方法返回

1



4

对象没有被调用者 retain 住。

1



5

释放池被清除, 对象被清除。

0




调用者并未retain 由方法返回的对象。结果, 释放池被清除时,对象也被清除了,所以调用者无须再释放对象了。
可以看到先前我们的问题得以解决, 对象的释放是发生在对象被方法返回之后,


NSAutorleasePool 类


Cocoa 的NSAutoreleasePool 类实现 释放池。 -autorelease 方法实现对象在释放池的添加和释放。
[object autorelease]; //将对象放入释放池,意味着稍后会被释放。
来看这个正确的方法:
-(NSObject *) correctMethod
{
    NSObject *result = [[NSObject alloc] init];
    [result autoreleqase];
    return result;
}
allocated 初始化之后,reference 被赋值给 result. reference count =1。 当 result 被 autorelease 时,对象被放入释放池。 reference count 仍为1。
如果调用-correctMethod的代码没有retain 返回的对象 (NSObject) ,那末对象的 reference count 将为零, 对象被清除, 释放池被清除。 如果调用代码retain 住返回对象, 对象的reference count 将暂时为2。 当释放池最终被清除时,对象的reference count 减少到1。但对象并未被清除。 调用代码所keep 住的reference 依然有效,。


release pool 是谁生成的?

Cocoa 程序使用App Kit 框架,在内部事件循环(event loop) 开始的时候自动生成release pool.  当程序代码执行结束, 控制返回到应用程序对象时(通常在事件循环的最后),应用程序对象发送 release 消息给 释放池。
当然,特殊情况下,比如要加强程序性能和减低程序的内存要求,或者,比如制作一个命令行程序,不会用到 App Kit 程序框架时,就需要自己生成释放池。
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
在事件循环最后,释放这个池:
[pool release];


release or autorelease ?

-release 方法要远比 -autorelease 效率高。 所以, 除非要使用 -autorelease 的特殊功能, 否则,尽量使用 - release. 过多使用 -autorelease 将导致程序运行缓慢。


新规则:



当alloc, copy, retain 一个对象后, 日后你必须负责释放对象, 用- release 或者 -autorelease 。如果你没有 alloc, copy, 或者 retain 过一个对象, 那就没有必要去 release 它。

alloc 或者 copy 之外的方法,当返回一个对象给你时,这个对象通常只在这个方法内有效,而且在方法的最后可以安全返回。你如果需要继续使用这个对象 (比如把对象存入一个实例变量), 就必须要磨 retain 要磨 copy 这个返回对象。

如果不再需要reference 一个对象,就应该使用 -autorelease 而不是 release. 同时,为了程序性能考虑, 尽量使用 -release 而不是 -autorelease.



【amazing cocos2d-x 3.0之十三】内存管理(1):引用计数(Reference Count)和自动释放池(AutoReleasePool)

1. 引用计数 引用计数shi

Java内存管理之软引用(Soft Reference)

软引用(Soft  Reference)的主要特点是具有较强的引用功能。只有当内存不够的时候才回收这类内存,因此在内存足够的时候,他们通常不被回收。另外,这些引用对象还能保证在Java  抛出OutO...

java 内存回收管理机制——Reference中四种引用方式

不仅仅是Andorid,在编写任何JAVA工作项目中我们都要考虑到内存泄漏和OOM的问题。在JDK的java.lang.ref包中提供了四种引用方式:强引用(StrongReference),软引用(...

ecos系统内存管理

  • 2017年11月17日 15:16
  • 25KB
  • 下载

Incorrect decrement of the reference count of an object that is not owned at this point by the calle

Incorrect decrement of the reference count of an object that is not owned at this point by the cal...

C++ 内存管理算法和实现.chm.rar

  • 2017年11月27日 10:17
  • 5.47MB
  • 下载

bitmap内存管理

  • 2017年02月20日 10:15
  • 1.03MB
  • 下载

linux 内存管理分析之-----SLAB层

SLAB层:               想必大多数人一提起linux内存管理,第一反应是"啊,特么的怎么这么复杂",哈哈,其实就是看书时蒙蔽了,别急,兄弟我陪你捋捋. 正经的来吧:  (1)    ...

qemu内存管理流程

  • 2017年05月25日 15:45
  • 208KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:内存管理 reference count
举报原因:
原因补充:

(最多只允许输入30个字)