《C#妹妹和Objective-C阿姨对话录》(04)垃圾回收基础--拆迁队那点事

C#妹妹:操作系统天天说控制内存空间价格,咋还这么高?我巨资购买的内存空间,后来发现竟然在硬盘上!虚拟内存!TMD!

Objective-C阿姨:操作系统全靠卖内存空间挣钱呢,你说价格能会降么?你看看那些程序员心理就平衡了,上海买房子结果买到江苏,北京买房子结果买到河北,上班还要跨省,天天面向对象,到头来连个对象都找不到。。

C#妹妹:靠,还是那句话“同一个世界 同一个噩梦”,你说内存空间卖光了咋办?

Objective-C阿姨:把你内存空间回收了再卖给别人呗。

C#妹妹:啊??!!人家在用的内存也回收啊?

Objective-C阿姨:废话,所有的内存都是操作系统的,只是借给你而已,操作系统让你强制退出,你有办法哇,把你干掉然后发个新闻稿,说“死者目前情绪稳定”就好了。,不信看看你的《内存空间证》上使用期限是多少?

C#妹妹:60ms?! 真TMD的!这么霸道,刚出台的《内存权法》就不管么?。

Objective-C阿姨:操作系统执行的是1949年制定的《垃圾回收暂行条例》,已经暂行60多年了⋯⋯再说维稳是一切工作的核心!听操作系统的话,让你卖空间就买,让你租就租,让你释放空间就释放。特别是不用的对象赶快释放掉。操作系统最讨厌占茅坑不拉屎,轻则强制释放,重则删除程序,尸骨无存。。

C#妹妹:还好,我们.NET程序请了个拆迁队“垃圾回收器”,专门干这个事情。发现有用不到的对象,就主动还给操作系统了,早点把内存交给操作系统,兴许给我的补偿内存地段好点,别在给我安排什么虚拟内存了,再说操作系统请的强制拆迁队比较野蛮,尽量不麻烦他们了。

Objective-C阿姨:呵呵,这是个好主意,不过.NET的垃圾回收器咋知道你用不到这些对象?会不会把正用的对象也拆迁了?

C#妹妹:所谓用不到,就是指代码里没有再引用这些对象,.NET的所有对象都是由局部变量, 全局变量, 静态变量, 指向托管堆的CPU寄存器,直接或者间接引用的,所以他们称之为“根”,垃圾回收器只需要从根出发,扫描这些根都引用了那些对象,并且全部记录下来,余下那些没有记录在册的对象就都可以回收了。拆除都是垃圾回收器自动进行的,程序员一般不用干预了,复杂些的对象程序员要在方法Finalize()里留下拆除方法,垃圾回收器拆除非托管资源还不太在行,还是需要程序员指点一下的。这个过程非常安全,正在使用的对象是不会被回收的。

Objective-C阿姨:垃圾回收器咋知道对象间的引用关系的?

C#妹妹:通过元数据啊,元数据描述了对象间的引用关系,并且.NET是类型安全的,对象指针只能指向相应的对象。

C#妹妹:Objective-C阿姨,您的内存是如何管理的?

Objective-C阿姨:Objective-C 2.0也是有垃圾回收机制的,但是只能在Mac OS X Leopard 以上的版本使用。

C#妹妹:Leopard?豹子?是个什么概念?

Objective-C阿姨:这个要从Mac的版本说起,Mac OS X各个版本都是些猫科动物啦,现在最新版本是Snow Leopard,今年夏天Lion可能会发布。

下面的图大概描述了Mac OS X的历史。

哪像你们东家MS那么没有创意,今年一个窗户,明年一个窗户的造;天天造窗户,哪有不碎玻璃的,这不三月底MS亚太研究中心大楼有玻璃掉下来了。

C#妹妹: ,还是继续说垃圾回收的事情好哇。。。

Objective-C阿姨:好吧,不批你们东家了。接着说,iPhone和iPad开发也是不支持垃圾回收的。

C#妹妹:内存就需要程序员主动释放是么?

Objective-C阿姨:没错,不过Cocoa已经进行了简化,看下面的例子吧。

首先要建立个被测试销毁的对象

#import "House.h"
//先建一个需要被删除的对象 House类
@implementation House
-(void) dealloc//Objective-C在销毁对象的时候会自动调用这个方法
{
    NSLog(@"房子被拆除了");
    [super dealloc];
}
@end

这个House类是空的,里边只有个dealloc方法,能在拆除的时候显示一条信息“房子被拆除了”。

C#妹妹:好杯具的房子

Objective-C阿姨:下面的程序调用这个House对象

    House *h1=[House new];
    NSLog(@"A.对象引用数量:%lu",[h1 retainCount]);
    [h1 retain];
    NSLog(@"B.对象引用数量:%lu",[h1 retainCount]);
    [h1 release];
    NSLog(@"C.对象引用数量:%lu",[h1 retainCount]);
    [h1 release ];

先说[h1 retainCount]表示由多少个地方引用这个h1实例(House的实例),但是这个统计是否准确跟系统关系不大,主要看程序员统计的是否准确。

Objective-C使用的是引用计数的方式来检测对象是否需要回收的,通过new、alloc创建的对象,计数器都是1。位置A对象刚被new实例话,所以引用数量是1;

如果这个对象被其他对象引用一次 调用一次 retain,引用的数量加1。位置B刚调用了retain,所以引用数量加1,所以显示2。

如果引用的某个对象释放该对象,调用一次release,引用的数量减1。位置C刚调用了release,所以引用数量减1,所以显示1。

最后又调用了一次release,这个时候这个实例的引用数量为0,说明这个实例已经不再使用了,Objective-C会自动调用该对象的dealloc方法,回收资源。所以显示了“房子被拆除了”~

与.NET的区别在于,.NET是垃圾回收器自动统计那些对象已经没有引用了,但是这个工作在Objective-C上,必须由程序员来完成。


上面的例子纯粹为了展示retain、release、retainCount,程序员强制通过 retain、release改变引用数量的统计值(引用数量当然没有改变),实际操作是肯定不会这样进行的。

看下面这个稍微实战一点的例子

    House *h1=[House new];//new后有一个引用
    House *h2;
    House *h3;
    NSLog(@"%lu",[h1 retainCount]);//返回1
    
    h2=h1;//h2也引用到这个对象上
    [h1 retain];//所以手动更新引用计数器 为2
    NSLog(@"%lu,%lu",[h1 retainCount],[h2 retainCount]);//返回2,2
    
    h3=h2;//h3也跑过来凑热闹,这个时候对象有3个引用了
    [h1 retain];//所以手动更新引用计数器 为3
    NSLog(@"%lu,%lu,%lu",[h1 retainCount],[h2 retainCount],[h3 retainCount]);//返回3,3,3
    
    h1=nil;//h1不再引用对象
    [h3 release];//计数器减1
    NSLog(@"%lu,%lu,%lu",[h1 retainCount],[h2 retainCount],[h3 retainCount]);//返回0,2,2
    
    h2=nil;//h2也不再引用对象
    [h3 release];//计数器减1
    NSLog(@"%lu,%lu,%lu",[h1 retainCount],[h2 retainCount],[h3 retainCount]);//0,0,1
    
    [h3 release];//计数减为0,表示该对象已经没有引用了,拆迁队一涌而上,回收对象的内存,并返回“房子被拆除了”

C#妹妹:基本看明白了,h1\h2\h3 三个变量折腾了半天,其实都是指向一个实例,不断的通过retain和release同步对象的引用数量,一旦引用数量为0(不是真正的引用数量,是程序员统计出来的引用数量为0),拆迁队就上去拆房子,对么?所以程序员统计对象引用的工作非常重要。而在.NET中,判断引用为0的工作是由垃圾回收器完成的。

Objective-C阿姨:是的,Objective-C就是这样管理内存的,不过这只是刚刚开始,下次有更复杂的例子和更简洁的方法。。

--

各位同学,本人学习Objective-C时间很短,学习Objective-C其实不是为了Mac、iPhone开发,并没有实用,
其实是一个C#用户学习Objective-C的学习笔记,学习的确切目的是帮助我理解C#,毕竟没有比较是不可能知道所谓C#的特点的
请大家批判的眼光看这个东西,如果发现和其他文章、书籍、评论、资料有冲突,请尽量以其他文章为准。并给我留言
也邀请所有高手积极拍砖,我正好用来盖房子~~~
《C#妹妹和Objective-C阿姨对话录》

(01)认识Objective-C--初次见面的问候 
(02)这就是类--阿姨的狗狗 
(03)NSString--再遇狗狗
(04)垃圾回收基础--拆迁队那点事
(05)自动释放池--拆迁队的外援 

        待续⋯⋯

posted @ 2011-04-20 08:53  小墨的童鞋  阅读(6405)  评论(33编辑  收藏  举报