内存管理原理----《Objective-C高级编程:iOS与OS X多线程和内存管理》读书笔记

原创 2014年01月16日 23:31:13
《Objective-C高级编程:iOS与OS X多线程和内存管理》读书笔记
作者:wangzz
转载请注明出处
如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号wangzzstrive来支持我,谢谢!

一、前言

这本书由日本人Kazuki Sakamoto和Tomohiko Furumoto所著,主要讲了ARC、Blocks、GCD三个模块。总体来说,书的内容讲的挺深的,小日本写的东西还真是不错。作者一直试图从原理上阐述ARC、block、GCD的实现机制,不像大部分国内相关书籍中只介绍其然,这是一本探索所以然的书。鉴于上述三个模块是每个试图在iOS开发上有所造诣的同学必须掌握的东西,强烈建议已经有一定Objective-C功底的同学看看。
从事iOS开发以来一直都是使用手动内存管理,因此对引用计数的理解还是比较透彻的。直到开发拉手团购6.0版的时候,开始使用ARC,上手后的感觉是以后的内存管理都是ARC的天下。在这本书中,作者也着重介绍了手动内存管理及其实现。书中讲的内容大部分之前都看过,不过自己看的不够系统。断断续续花了二十天左右时间读完这本书,还是收获不小,下面将自认为值得记住的地方列举出来:

二、引用计数原理

iOS中说到内存管理,不管是手动还是ARC,都离不开引用计数,我一直很好奇引用计数到底是怎么存储的呢?可能的实现方式有两种:
  • 鉴于Objective-C对象都有引用计数,所以每个对象都应该存储自己的引用计数
  • runtime统一存储所有对象的引用计数
GNUstep使用的是前一种思想,在这里就不详述了。
苹果的实现方式是后一种----runtime采用散列表来管理引用计数,存储形式如下图所示:

苹果在实现时,凡是使用引用计数的方法,包括retainCount、retain、release方法都调用了同一个方法,该方法的实现原理简化后如下所示:
int _CFDoExternRefOperation(uintptr_t op, id obj)
{
  CFBasicHashRef table = 取得对象的散列表(obj);
  int count;

  switch(op) {
  case OPERATION_retainCount;
    count = CFBasicHashGetCountOfKey(table, obj);
    return count;
  case OPERATION_retain:
    CFBasicHashAddValue(table, obj);
    return obj;
  case OPERATION_release:
    count = CFBasicHashRemoveValue(table, obj);
    return 0 == count;
  }
}
这一个方法就解释了引用计数的实现原理!
苹果这种实现方式的优点是:
不用再每个对象内存块中考虑引用计数所站的内存;
引用计数表中存储的有各个对象的内存地址,可以直接通过各条引用技术追踪到对应的对象内存块,在调试的时候很有用。

三、__autoreleasing关键字

看我完这本书后,对该修饰符有了更深的理解,有以下几个方面:
1、ARC下使用__autoreleasing修饰符修饰的变量会被注册到autoreleasepool中,和非ARC下调用autorelease方法的效果相同;
2、当方法名不是alloc/new/copy/mutableCopy时,使用return返回的对象强引用会被自动注册到autoreleasepool。比如:
+ (id)array
{
  id obj = [[NSArray alloc] init];
  return obj;
}
上述代码中,因为没有指定所有权修饰符,id obj就是默认的id __strong obj,即obj是强引用,这时,obj就会被添加到autoreleasepool中。
3、访问附有__weak修饰符的变量时,该变量会被自动注册到autoreleasepool中,比如:
id __weak obj1 = obj0;
NSLog("class=%@", [obj1 class]);

//等价于以下代码

id __weak obj1 = obj0;
id __autoreleasing tmp = obj1;
NSLog("class=%@", [tmp class]);
这种等价是编译器自动做的转换,原因是__weak修饰符支持有对象的弱引用,在访问引用对象的过程中,该对象可能被释放。而如果将该对象加入到autoreleasepool中,在pool被释放之前,tmp对该对象的引用都是有效的。
4、_objc_autoreleasePoolPrint()函数
该函数属于私有函数,可以打印出注册到调用函数处所属的autoreleasepool中的对象。

四、__weak关键字

这部分需要着重介绍的是__weak关键字。
我们知道,当一个__weak类型的指针指向的对象被释放时,该指针会自动被置成nil,因此__weak关键字修饰的指针又被称为智能指针。那么这个功能是如何实现的呢?
1、编译器做的事
先看下面这段代码:
{
  id __weak obj1 = obj;
}
会被编译器编译成下面的模拟代码:
id obj1;
objc_initWeak(&obj1, obj);
objc_destoryWeak(&obj1);
即编译器会通过objc_initWeak函数初始化__weak修饰的变量,当变量的作用域结束后会通过objc_destoryWeak函数释放该变量。objc_initWeak函数实际干的活是:
objc1 = 0;
objc_storeWeak(&obj1, obj);
这里是先将指针objc1置成0,再调用objc_storeWeak函数使得obj1指向obj对象。
接下来的objc_destoryWeak函数的实际操作如下:
objc_storeWeak(&obj1, 0);
也就是说,让obj1指针指向的内容变成空。
总结一下,刚才的整个过程模拟代码如下:
id obj1;
obj1 = 0;
objc_storeWeak(&obj1, obj);
objc_storeWeak(&obj1, 0);
2、__weak实现原理
实际上,objc_storeWeak函数会把第二个参数的对象的地址作为key,并将第一个参数(__weak关键字修饰的指针的地址)作为值,注册到weak表中。如果第二个参数为0(说明对应的对象被释放了),则将weak表中将整个key-value键值对删除,这就是__weak关键字的核心思想!
weak表和引用计数表类似,都是通过hash表实现的。如果使用weak表,将被释放的对象地址作为key去检索,就能很高效的获取对应的指向该对象的类型为__weak的指针变量的地址。同时很容易理解,一个对象可能有多个__weak指针指向,因此一个对象地址key可能对应多个值。
在调用对象的release方法时,会在其中一步调用objc_clear_deallocating函数,该函数会执行以下操作:
  • 以当前对象的地址作为key,从weak表中获取对应的值----指向该对象的__weak类型的指针变量;
  • 将取到的所有指针变量的值赋值为nil;
  • 从weak表中删除该key对应的整条记录。
根据以上步骤,前面介绍过的__weak关键字修饰的对象指针所指向的对象被释放时,指针被置为nil就可以实现了。同时由此可知,如果大量使用附有__weak修饰符的变量会消耗响应的CPU资源,因此,应该尽量少使用__weak修饰符。


C++多线程内存管理

  原文:http://yachang.wang.blog.163.com/blog/static/35551220200762753057335/  假设有一个进程,创建了两个线程A、B,线程A在堆...
  • memory01
  • memory01
  • 2011年05月16日 17:00
  • 5886

面试总结------Java内存管理与多线程

面试总结——Java内存管理与多线程1. 什么是线程?什么是进程?同一进程下的线程共享线程:程序在执行过程中,能够执行程序代码的一个执行单元,一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之...
  • jianyuerensheng
  • jianyuerensheng
  • 2016年11月14日 09:57
  • 1897

有关多线程和内存管理的学习

有关多线程和内存管理的学习 内存管理的思考方式 - 如下四点 自己生成的对象,自己持有 非自己生成的对象,自己也能持有 不再需要自己持有的对象时释放 非自己持有的对象无法释放 有关”生成”、”...
  • iOS_yangt
  • iOS_yangt
  • 2016年01月21日 16:36
  • 601

《Objective-C 高级编程 iOS与OS X多线程和内存管理》 核心札记一

苹果源代码不会告诉你的 ——引子 近日偶借一本图灵出版的程序书籍,是由日本资深软件工程师 K.S. (Twitter:@splhack) 和 TF (Twitter:@munakoiso)...
  • LIN1986LIN
  • LIN1986LIN
  • 2014年07月14日 16:09
  • 730

内存管理原理----《Objective-C高级编程:iOS与OS X多线程和内存管理》读书笔记

《Objective-C高级编程:iOS与OS X多线程和内存管理》读书笔记 作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/detail...
  • wzzvictory_tjsd
  • wzzvictory_tjsd
  • 2014年01月16日 23:31
  • 8314

《Objective-C高级编程:iOS与OS X多线程和内存管理》读后感

显然,这不是一本面向初学者的书,
  • zhangao0086
  • zhangao0086
  • 2014年08月30日 12:10
  • 8970

读《Objective-C高级编程iOS与OS X多线程和内存管理》

最近一周,公司在广州有发布会。去广州的人很忙,留在公司的开发人员有时也很“忙”。趁着空闲的时间,看了《Objective-C高级编程iOS与OS X多线程和内存管理》这书,网上找的pdf版本。 ...
  • zhuming3834
  • zhuming3834
  • 2016年03月10日 15:31
  • 778

Objective-C高级编程:iOS与OS X多线程和内存管理读书笔记

Objective-C高级编程:iOS与OS X多线程和内存管理自动引用计数 自动引用计数(ARC,Automatic Reference Counting) “在LLVM编辑器中设置ARC为有效...
  • abai_ww
  • abai_ww
  • 2015年10月14日 16:22
  • 778

《Objective-C 高级编程 iOS与OS X多线程和内存管理》 核心札记二

核心札记二 Blocks   阅读地点:北京 肯德基店 1,Blocks 是C 语言的扩充功能,用一句话概述就是:带有自动变量(局部变量,作者将此翻译成自动变量)的匿名函数; 2,Blocks 类...
  • mapboo
  • mapboo
  • 2014年04月08日 13:56
  • 1159

《Objective-C 高级编程 iOS与OS X多线程和内存管理》 核心札记一

苹果源代码不会告诉你的
  • mapboo
  • mapboo
  • 2014年04月07日 01:19
  • 2126
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:内存管理原理----《Objective-C高级编程:iOS与OS X多线程和内存管理》读书笔记
举报原因:
原因补充:

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