《Objective-C高级编程》の内存管理の学习笔记
此日志用于记录下学习过程中碰到的问题 
转载请注明出处: http://www.cnblogs.com/xdxer/p/4069650.html
《Objective-C高级编程》 人民邮电出版社 是一本写的很棒的书,日本作者对于细节抠的很仔细,深入浅出,推荐学习Objective-C的同学们购买。
#1 关于retainCount 变量在内存中是如何存放的?
在GNUStep(一种cocoa框架的互换框架)中retainCount和对象放置在一起,在对象地址之前。所以有如下获取GNUstep中retainCount的方式:
-(NSUInteger) retainCount
{
return NSExtraRefCount(self) + ;
} inline NSUInteger
NSExtraRefCount(id anObject)
{
return ((struct obj_layout *) anObject )[-].retained;
}
不过苹果的实现是管理了一张hashTable,在通过hash(obj),在相应的位置加入该对象的引用技术retainCount和对象内存块的地址。
虽然GNUstep的实现方式可能会更加直观一些,不过苹果这么做也是有相应的好处的:
- 对象的内存块分配无需考虑内存块的头部。
- 引用计数表中各记录中存有内存块地址,可从各个记录追溯到各个对象的内存块。在调试过程中很重要。另外在利用工具监测内存泄漏时,引用计数表中的各记录也有助于监测各对象的持有者是否存在。
#2 autorelease & NSRunloop ?
NSAutoreleasePool这个类对于pool对象使用了管理者模式,即会管理许多个pool 并且记录当前正在使用的pool,如果在别的地方使用了 [[[class alloc] init] autorelease],那么该对象就会被加入这个正在使用的pool中。
- [pool drain] 方法会废弃该pool 并且对pool中的所有对象进行一次release;
- 新定义的pool总是当前正在使用的pool,所以在多个NSAutoreleasePool嵌套使用时,加入的总是最内层的pool;
- NSRunloop象征着程序的主循环,每次NSRunloop开始的时候都会定义一个autoreleasepool,当Runloop结束的时候会调用该pool的drain方法。具体的NSRunloop在后续章节中会有介绍。
#3 如何提高Objective-C方法的调用速度?
“IMP Caching”方法
提高频繁调用的autorelease方法的速度:例
id autorelease_class = [NSAutoreleasePool class];
SEL autorelease_sel = @selector(addObject:);
IMP autorelease_imp = [autorelease_class methodForSelector:autorelease_sel]; - (id) autorelease
{
(* autorelease_imp)(autorelease_class,autorelease_sel,self);
} - (id)autorelease
{
[NSAutoreleasePool addObject:self];
}
在框架初始化的时候对,这几个方法进行了缓存。第一种autorelease的调用速度是后者的2倍。因为Oc-runtime 中有对象之间发送消息的开销。
#4 SEL 和 IMP的区别?
typedef struct objc_selector *SEL;
typedef id (*IMP)(id, SEL, ...);
IMP 是一个函数指针,这个被指向的函数包含一个接收消息的对象id(self 指针), 调用方法的选标 SEL (方法名),以及不定个数的方法参数,并返回一个id。也就是说 IMP 是消息最终调用的执行代码,是方法真正的实现代码 。我们可以像在C语言里面一样使用这个函数指针。
#5 _weak 赋值给 _strong 时的情况?
- 如果_strong 变量为nil , _weak对象所指的对象的引用计数器加1;
- 如果_strong 变量为某个对象那么,会hash(obj) 调用内部的release,然后将_weak所指的对象的引用计数器加1;
- 如果_strong 变量和_weak所指的都是一个对象,那么不做任何操作。(如果是release之后retain ?那么绝对会出现问题,如果刚好_strong所指的对象的retainCount为1,待验证)
- 如果_weak 所指为nil , 那么等同于 obj = nil; 对于原先指向对象的retainCount –1 ;
#6 _unsafe_unretained 为何物?
实际上就是不会自动置nil的指针 (_weak),所以可能会出现野指针。
#7 @autorelease 块
在块结束的时候调用,[pool drain] ;
#8 C++智能指针的问题 std:: shared_ptr & std:: weak_ptr & std:: auto_ptr
引入了引用计数器的概念。
#9 NSZone是什么?
在碰到allocWithZone, copyWithZone总会有个疑问,这个NSZone到底是个什么东西?简单来说,可以想象成一个内存池,alloc或是dealloc这些操作,都是在这个内存池中操作的。cocoa总是会配置一个默认的NSZone,任何默认的内存操作都是在这个“zone”上操作的。默认的NSZone的缺陷在于,它是全局范围的,时间一长,必然会导致内存的碎片化,如果你需要大量的alloc一些object,那么性能就会受到一些影响。所有cocoa提供方法,你可以自己生成一个NSZone,并将alloc, copy全部限制在这个“zone”之内。
#10 在删除动态数组的时候需要注意的?
需要讲所有元素置为nil,不然会发生内存泄漏。即使使用memset等函数将内存填充为0也不会释放所赋值的对象。对于编译器,必须明确得使用赋值给附有_strong 修饰的变量的源代码。
for( NSUInteger i = ; i < entries ;++i )
array[i] = nil ;
free(array);
#11 _weak表
在ARC条件下,当_weak指向的对象被释放了,那么_weak会自动被置为nil,那么runtime中是如何做到这一点的呢?
在内存中维护一张weak表。
/* oc代码 */
{
id __weak obj1 = obj;
}
/* 编译器模拟代码 */
id obj1;
objc_initWeak(&obj1,obj);
objc_destroyWeak(&obj1);
如上述代码,key 为对象的地址 obj ,values为 _weak的地址&obj1 。 一个对象地址可以对应很多个_weak变量地址,当一个对象被析构,那么他在weak表中所指向的_weak变量就会被置为nil。然后在weak表中删除该记录。
由于使用_weak变量会造成以上的系统开销,所以仅在需要避免循环引用的时候使用__weak修饰符。
#12 在ARC条件下如何获取retainCount ?
使用: _objc_rootRetainCount(obj);
《Objective-C高级编程》の内存管理の学习笔记的更多相关文章
- C++内存管理学习笔记(5)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
- C++内存管理学习笔记(6)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
- C++内存管理学习笔记(7)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
- C++内存管理学习笔记(4)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
- C++内存管理学习笔记(2)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
- C++内存管理学习笔记(1)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
- C++内存管理学习笔记(3)
/****************************************************************/ /* 学习是合作和分享式的! /* Auth ...
- Linux内存管理学习笔记 转
https://yq.aliyun.com/articles/11192?spm=0.0.0.0.hq1MsD 随着要维护的服务器增多,遇到的各种稀奇古怪的问题也会增多,要想彻底解决这些“小”问题往往 ...
- Linux内存管理学习笔记——内存寻址
最近开始想稍微深入一点地学习Linux内核,主要参考内容是<深入理解Linux内核>和<深入理解Linux内核架构>以及源码,经验有限,只能分析出有限的内容,看完这遍以后再更深 ...
随机推荐
- Cts框架解析(15)-任务运行完
case运行完成后.会回到CtsTest的run方法中: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaXRmb290YmFsbA==/font/5a6L ...
- javacript中apply和call的区别
apply:方法能劫持另外一个对象的方法,继承另外一个对象的属性. 接受的参数是一个字符串. call:和apply的意思一样,只不过是参数列表不一样. 接收的参数是一个数组. 例如: <s ...
- 3D打印技术之切片引擎(4)
[此系列文章基于熔融沉积( fused depostion modeling, FDM )成形工艺] 这一篇文章我讲一下多边打印的问题,多边打印是切片引擎的一项关键的技术. 图1 双边打印 首先.它能 ...
- cuda9,cuda8分享百度云下载
一.文件名称: md5-cuda9cuda-repo-ubuntu1704-9-0-local_9.0.176-1_amd64.debcuda-repo-ubuntu1604-9-0-local_9. ...
- java 对账关键点
原理:双方交易信息对比是否平账 注意:对账bean必须重写 equals 方法 如图: //对账方法
- multimap容器和multiset容器中的find操作
前言 multimap容器是map容器的“ 增强版 ”,它允许一个键对应多个值.对于map容器来说,find函数将会返回第一个键值匹配元素所在处的迭代器.那么对于multimap容器来说,find函数 ...
- 自译Solr in action中文版
文件夹 Part 1 初识 SOLR 1 Solr 简单介绍 2 開始熟悉 Solr 3 Solr 核心概念 4 配置 Solr 5 建立索引 6 文本分析 Part 2 Solr 核心功能 7 发起 ...
- JAVA虚拟机、Dalvik虚拟机和ART虚拟机简要对照
1.什么是JVM? JVM本质上就是一个软件,是计算机硬件的一层软件抽象,在这之上才干够运行Java程序,JAVA在编译后会生成相似于汇编语言的JVM字节码,与C语言编译后产生的汇编语言不同的是,C编 ...
- 远程访问Linux的常见方式
访问方式 不加密文字界面:telnet.rsh 加密文字界面:SSH 图形界面:Xdmcp.RDP.VNC SSH SSH用来取代finger.R shell(rlogin.rcp.rsh).teln ...
- BZOJ3627: [JLOI2014]路径规划
BZOJ3627: [JLOI2014]路径规划 Description 相信大家都用过地图上的路径规划功能,只要输入起点终点就能找出一条最优路线.现在告诉你一张地图的信息,请你找出最优路径(即最短路 ...