第六章 垃圾回收

垃圾回收:

垃圾回收指的是程序运行过程中,检查是否有不再使用的对象,并自动释放他们所占用的内存,通常被简称为GC。内存的检查和回收都是由垃圾收集器完成的。

在OC2.0中,垃圾回收首先进行的工作就是识别不允许被回收的对象。全局变量,静态变量和栈内临时变量他们所引用的对象不允许被回收。这些对象称为根集合。如果一个对象的实例变量引用了不允许被回收的对象或根集合中的对象,那么这个对象也不允许被回收。也就是说,通过全局变量,静态变量或者栈内变量的强引用而查找到的对象都不可以被回收。反之,只要是从根集合出发无法到达的对象都属于垃圾回收的目标。

对于不再使用的对象我们可以通过为其赋值nil来明确表示其已不再被使用,据此通知垃圾收集器回收该对象。这种做法不仅有助于垃圾回收,也是一种良好的编程风格。

垃圾收集器整个回收过程完全是根据程序占用内存的多少自动完成的。一个程序只有一个垃圾收集器,通常在mainthread中运行。它通常作为一个单独的线程运行。垃圾收集器运行的时候有可能会暂停其他线程来完成垃圾收集。

主动启动垃圾回收:通过给类NSGarbageCollector发送collectIfNeeded消息来启动垃圾收集器。通过主动启动垃圾回收,不仅可以控制内存消费,又可以避免垃圾回收突然启动时程序反应变慢的问题。

finalize方法的定义:

finalize方法被定义在NSObject中,在对象被回收之前,finalize方法会被执行。原则上不推荐轻易定义finalize,因为finalize方法作为垃圾回收的一部分被执行,垃圾回收在一个独立的线程中进行。同软件本身是并行关系,如果finalize处理过于复杂的话就会影响软件本身的执行速度。另外,要被释放的对象的finalize方法的执行是没有先后顺序的。不要依赖finalize方法的执行顺序来做任何事情。

实现finalize方法的时候要注意下面这些事项:

finalize方法内不用担心其他对象的释放。

要注意finalize方法中对象的赋值。

finalize的执行顺序和对象的释放顺序都是无法确定的。

finalize不是线程安全的。

对象的善后处理应该在这个对象不再使用的时候进行,而不要在finalize 方法中进行。特别是文件之类的资源对象,不要在finalize方法中进行关闭处理。进行善后处理之后,可以将不再使用的对象赋值为别的对象或者nil,以取消对该对象的引用,并告知垃圾收集器该对象可以被清理了。

反之,在多个地方释放对象时,就不得不用到finalize方法。

使用垃圾回收编程小结:

·编译的时候需要使用编译选项fobjc-gc-only

·使用局部变量给方法中的局部对象赋值

·如果暂时不想垃圾回收某对象,需要保证该对象能够被全局变量引用

·原则上垃圾回收只负责回收id类型或类类型的变量

·不用考虑所有权的问题,也不用考虑实例变量的问题

·释放对象时的一些“善后”操作可以写在finalize方法中,但除了不写在finalize中就无法实

现的功能,要尽量减少通过finalize完成的操作

·引用计数相关的方法和dealloc方法不会被执行

分代垃圾回收:

启用垃圾回收后,会在变量赋值,改写变量时建立写屏障。OC2.0利用修改变量时的信息采用分代垃圾回收的方式来进行内存管理。分代垃圾回收并不会每次对整个堆空间进行遍历,而是以新生成的对象为中心,以尽可能快速的收集那些生命周期短的对象,通过这种分代的方法,既可以减轻垃圾回收的处理负荷,又能有效释放空间,但也要小心这种方法会积攒太多的陈旧对象。

弱引用:

和ARC不一样的是,栈内的临时变量不能声明为弱引用。同时也可以使用_ _ strong修饰符来声明一个变量是强引用类型。除了这两个修饰符外,_ _autoreleasing和_ _unsafe_unretained等其他生命期修饰符在垃圾回收中都不可用。

弱引用的作用在于解决强引用所带来的对象之间在存活时间上的耦合关系。

尽量不要使用这种依赖于垃圾回收的运行频率和时机的编程方法。

通过垃圾回收回收动态分配的内存:

通过NSAllocateCollectable()分配的内存因为可以通过垃圾回收被自动回收,所以可以不考虑内存释放的问题,比使用malloc和free编程更方便。但指向初对象之外的动态内存的指针变量都需要用_ _strong来修饰。另外,程序的效率有可能会降低,所以并不需要特意把原来使用的malloc/free的代码都改为NSAllocateCollectable。

_ _ strong修饰符的使用方法:

修饰对象类型的变量。

修饰指针类型的变量。被_ _strong修饰的指针所指向的内存可以被垃圾回收,但要等到该指针不再使用为止。

用于修饰函数或方法返回的指针类型。指针指向的内存属于垃圾回收的范畴,但如果被赋值给一个强引用类型的变量,就暂时不能被回收。

NSGarbageCollector类:

+ (id)defaultCollector  //返回现在有效的垃圾收集器的实例,如果垃圾收集无效,则返回nil。

- (void)collectIfNeeded //申请进行垃圾回收。这个方法被调用之后会判断当前内存使用情况,如果觉得需要进行垃圾回收就会启动垃圾收集器。典型的调用方式如下:

[[NSGarbageCollectordefaultCollector]collectIfNeeded];

- (void)collectExhaustively //申请进行垃圾回收。希望使用深度遍历以尽可能地释放更多的内存时使用。这个方法被调用之后会判断当前内存使用情况,如果觉得需要进行垃圾回收就会启动垃圾收集器。

- (void)disableCollectorForPointer:(void *)ptr //调用这个函数之后,这个指针所指向的内存不会被回收。也就是说指针指向的对象会变成根集合中的对象。如果想让对象变为可以被再次回收的话,需要调用下面的enableCollectorForPointer:

- (void)enableCollectorForPointer:(void *)ptr //能够让通过disableCollectorForPointer:指定不允许被释放的内存或对象再次允许被释放。

- (void)enable

- (void)disable //disable方法能让垃圾收集器暂时停止内存回收。enable方法则能让垃圾收集器恢复工作。但enable和disable不许成对使用。这两个函数一般被用于防止多线程中同时运行垃圾回收。

- (BOOL)isEnabled //用于判断垃圾回收器是否有效,有效时返回真。

实时API:

控制垃圾回收器的动作。

void objc_startCollectorThread (void); //启动一个线程专门运行垃圾收集器。

oid *objc_memmove_collectable(void *dst, const void *src, size_t size); //复制垃圾回收对象的内存时使用该函数替代memcpy和memmove。

内存管理方式的比较:

首先让我们来看看和手动内存管理相比,ARC和垃圾回收有哪些优点。

·不需要再在意对象的所有权

·可以删除程序中内存管理部分的大部分代码,使程序看起来更清爽

·可以避免手动内存管理时的错误(内存泄漏等)

·不需要再在意引用计数内存管理中的一些特殊用法。例如访问方法的定义和临时对象的使用等

·可以使多线程环境下的编程更简单。例如:不用担心不同的线程之间可能出现的所有权冲突

垃圾回收的缺点如下所示。

·垃圾收集器运行时会影响程序的速度

·需要不停地监视内存的使用,同引用计数的方法相比,程序的速度会变慢

·会影响程序的效率。不经常使用的内存也会被垃圾收集器不时地访问,实际上有可能会占用

更多的内存

·需要使用一些技巧来让对象被回收或不被回收

·无法使用引用计数管理方式下的一些设计方针。例如:事先准备好一些管理文件或其他资源类的对象,在对象被释放的同时关闭资源

相比较而言,ARC没有垃圾回收那么多缺点,但也有一些要注意的地方

·循环引用一旦形成就不会自己消失

·为了防止循环引用的形成,需要注意对象间的关系。GUI的各个类之间也有可能形成循环引

用,也要注意防止循环引用的形成

·理论上可被赋值的对象都可以被自动释放,但在处理结构体、数组、二重指针等类型的变量

时有一些限制

·需要注意Core Foundation的对象和Objectve-G的对象之间的转换(详情请参考附录B)

更改内存管理方式:

与对象的所有权和生存期相关的处理

释放对象之后的善后处理

防止野指针的生成

有时还需要从对象之间的相互关系来重新考虑

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 1.什么是垃圾回收? 垃圾回收(Garbage Collection)是Java虚拟机(JVM)垃圾回收器提供...
    简欲明心阅读 89,348评论 17 311
  • 1. 垃圾回收的意义在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象;而在...
    爱情小傻蛋阅读 916评论 0 11
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,560评论 18 399
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,169评论 11 349
  • 那些平时发生在很多人身上的这样那样不顺心的事情,都是因为在乎的太多,太注重自己的感受,结果反而会给自己招来更多的烦...
    白桦i阅读 153评论 0 0