iOS内存管理Word下载.docx
- 文档编号:3784673
- 上传时间:2023-05-02
- 格式:DOCX
- 页数:21
- 大小:112.17KB
iOS内存管理Word下载.docx
《iOS内存管理Word下载.docx》由会员分享,可在线阅读,更多相关《iOS内存管理Word下载.docx(21页珍藏版)》请在冰点文库上搜索。
6.
7.}
8.
9.
10.+
(NSZone*)z
11.
12.{
13.
14.return
NSAllocateObject
(self,
0,
z);
15.
16.}
GNUstep/modules/core/base/Source/NSObject.mNSAllocateObject:
1.struct
obj_layout
{
3.NSUInteger
retained;
5.};
7.
9.NSAllocateObject(Class
aClass,
NSUInteger
extraBytes,
NSZone
*zone)
10.
11.{
12.
13.int
size
=
计算容纳对象所需内存大小;
14.
15.id
new
NSZoneCalloc(zone,
1,
size);
16.
17.memset
(new,
18.
19.new
(id)&
((obj)new)[1];
20.
21.}
NSAllocateObject函数通过调用NSZoneCalloc函数来分配存放对象所需的空间,之后将该内存空间置为nil,最后返回作为对象而使用的指针。
我们将上面的代码做简化整理:
GNUstep/modules/core/base/Source/NSObject.malloc简化版本:
9.+
sizeof(struct
obj_layout)
+
对象大小;
15.struct
*p
(struct
*)calloc(1,
17.return
(id)(p+1)
19.return
alloc类方法用structobj_layout中的retained整数来保存引用计数,并将其写入对象的内存头部,该对象内存块全部置为0后返回。
一个对象的表示便如下图:
4.2GNU–retain
GNUstep/modules/core/base/Source/NSObject.mretainCount:
1.-
(NSUInteger)
retainCount
NSExtraRefCount(self)
1;
10.inline
12.NSExtraRefCount(id
anObject)
14.{
16.return
((obj_layout)anObject)[-1].retained;
17.
18.}
GNUstep/modules/core/base/Source/NSObject.mretain:
retain
5.NSIncrementExtraRefCount(self);
7.return
self;
9.}
13.inline
void
15.NSIncrementExtraRefCount(id
17.{
19.if
(((obj)anObject)[-1].retained
==
UINT_MAX
-
1)
21.[NSException
raise:
NSInternalInconsistencyException
22.
23.format:
@"
NSIncrementExtraRefCount()
asked
to
increment
too
far”];
24.
25.((obj_layout)anObject)[-1].retained++;
26.
27.}
以上代码中,NSIncrementExtraRefCount方法首先写入了当retained变量超出最大值时发生异常的代码(因为retained是NSUInteger变量),然后进行retain++代码。
4.3GNU–release
和retain相应的,release方法做的就是retain--。
GNUstep/modules/core/base/Source/NSObject.mrelease
(oneway
void)
release
5.if
(NSDecrementExtraRefCountWasZero(self))
7.{
9.[self
dealloc];
11.}
13.}
17.BOOL
19.NSDecrementExtraRefCountWasZero(id
21.{
23.if
0)
25.{
27.return
YES;
28.
29.}
30.
31.((obj)anObject)[-1].retained--;
32.
33.return
NO;
34.
35.}
4.4GNU–dealloc
dealloc将会对对象进行释放。
GNUstep/modules/core/base/Source/NSObject.mdealloc:
(void)
dealloc
5.NSDeallocateObject
(self);
12.NSDeallocateObject(id
16.obj_layout
o
&
((obj_layout)anObject)[-1];
18.free(o);
19.
20.}
4.5Apple实现
在Xcode中设置Debug->
DebugWorkflow->
AlwaysShowDisassenbly打开。
这样在打断点后,可以看到更详细的方法调用。
通过在NSObject类的alloc等方法上设置断点追踪可以看到几个方法内部分别调用了:
retainCount
1.__CFdoExternRefOperation
2.CFBasicHashGetCountOfKey
retain
2.CFBasicHashAddValue
release
2.CFBasicHashRemoveValue
可以看到他们都调用了一个共同的__CFdoExternRefOperation方法。
该方法从前缀可以看到是包含在CoreFoundation,在CFRuntime.c中可以找到,做简化后列出源码:
CFRuntime.c__CFDoExternRefOperation:
1.int
__CFDoExternRefOperation(uintptr_t
op,
id
obj)
3.CFBasicHashRef
table
取得对象的散列表(obj);
5.int
count;
9.switch
(op)
11.case
OPERATION_retainCount:
13.count
CFBasicHashGetCountOfKey(table,
obj);
15.return
17.break;
19.case
OPERATION_retain:
21.count
CFBasicHashAddValue(table,
23.return
obj;
25.case
OPERATION_release:
27.count
CFBasicHashRemoveValue(table,
29.return
0
31.}
33.}
所以__CFDoExternRefOperation是针对不同的操作,进行具体的方法调用,如果op是OPERATION_retain,就去掉用具体实现retain的方法。
从BasicHash这样的方法名可以看出,其实引用计数表就是散列表。
key为hash(对象的地址)value为引用计数。
下图是Apple和GNU的实现对比:
5autorelease和autorelaesepool
在苹果对于NSAutoreleasePool的文档中表示:
每个线程(包括主线程),都维护了一个管理NSAutoreleasePool的栈。
当创先新的Pool时,他们会被添加到栈顶。
当Pool被销毁时,他们会被从栈中移除。
autorelease的对象会被添加到当前线程的栈顶的Pool中。
当Pool被销毁,其中的对象也会被释放。
当线程结束时,所有的Pool被销毁释放。
对NSAutoreleasePool类方法和autorelease方法打断点,查看其运行过程,可以看到调用了以下函数:
1.NSAutoreleasePool
*pool
[[NSAutoreleasePool
alloc]
init];
3.//
等同于
objc_autoreleasePoolPush
5.
7.id
obj
[[NSObject
9.[obj
autorelease];
11.//
objc_autorelease(obj)
15.[NSAutoreleasePool
showPools];
17.//
查看
NSAutoreleasePool
状况
21.[pool
drain];
23.//
objc_autoreleasePoolPop(pool)
[NSAutoreleasePoolshowPools]可以看到当前线程所有pool的情况:
1.objc[21536]:
##############
3.objc[21536]:
AUTORELEASE
POOLS
for
thread
0x10011e3c0
5.objc[21536]:
2
releases
pending.
7.objc[21536]:
[0x101802000]
................
PAGE
(hot)
(cold)
9.objc[21536]:
[0x101802038]
################
POOL
0x101802038
11.objc[21536]:
[0x101802040]
0x1003062e0
NSObject
13.objc[21536]:
15.Program
ended
with
exit
code:
在objc4中可以查看到AutoreleasePoolPage:
1.objc4/NSObject.mm
AutoreleasePoolPage
3.
5.class
9.static
inline
*push()
13.生成或者持有
类对象
15.}
17.static
pop(void
*token)
19.{
21.废弃
23.releaseAll();
25.}
27.static
autorelease(id
29.{
31.相当于
类的
addObject
类方法
33.AutoreleasePoolPage
*page
取得正在使用的
实例;
36.
37.id
*add(id
38.
39.{
40.
41.将对象追加到内部数组
42.
43.}
44.
45.void
releaseAll()
46.
47.{
48.
49.调用内部数组中对象的
方法
50.
51.}
52.
53.};
54.
55.
56.
57.void
*
58.
59.objc_autoreleasePoolPush(void)
60.
61.{
62.
63.if
(UseGC)
return
nil;
64.
65.return
AutoreleasePoolPage:
:
push();
66.
67.}
68.
69.
70.
71.void
72.
73.objc_autoreleasePoolPop(void
*ctxt)
74.
75.{
76.
77.if
return;
78.
79.AutoreleasePoolPage:
pop(ctxt);
80.
81.}
AutoreleasePoolPage以双向链表的形式组合而成(分别对应结构中的parent指针和child指针)。
thread指针指向当前线程。
每个AutoreleasePoolPage对象会开辟4096字节内存(也就是虚拟内存一页的大小),除了上面的实例变量所占空间,剩下的空间全部用来储存autorelease对象的地址。
next指针指向下一个add进来的autorelease的对象即将存放的位置。
一个Page的空间被占满时,会新建一个AutoreleasePoolPage对象,连接链表。
6__unsafe_unretained
有时候我们除了__weak和__strong之外也会用到__unsafe_unretained这个修饰符,那么我们对__unsafe_unretained了解多少?
__unsafe_unretained是不安全的所有权修饰符,尽管ARC的内存管理是编译器的工作,但附有__unsafe_unretained修饰符的变量不属于编译器的内存管理对象。
赋值时即不获得强引用也不获得弱引用。
来运行一段代码:
1.id
__unsafe_unretained
obj1
5.id
__strong
obj0
8.obj1
obj0;
11.NSLog(@"
A:
%@"
obj1);
16.NSLog(@"
B:
运行结果:
1.2017-01-12
19:
24:
47.245220
__unsafe_unretained[55726:
4408416]
3.2017-01-12
47.246670
5.Program
对代码进行详细分析:
5.//
自己生成并持有对象
因为
变量为强引用,
13.//
所以自己持有对象
15.obj1
19.//
虽然
变量赋值给
21.//
但是
变量既不持有对象的强引用,也不持有对象的弱引用
23.NSLog(@"
25.//
输出
变量所表示的对象
29.
31.NSLog(@"
33.//
35.//
变量表示的对象已经被废弃
37.//
所以此时获得的是悬垂指针
39.//
错误访问
所以,最后的NSLog只是碰巧正常运行,如果错误访问,会造成crash
在使用__unsafe_unretained修饰符时,赋值给附有__strong修饰符变量时,要确保对象确实存在
【编辑推荐】
1.iOS抓取HTML,CSSXPath解析数据
2.iOS与Android开发——我们该如何选择?
3.用Jenkins搭建iOS/Android持续集成打包平台
4.iOS10个实用小技巧(总有你不知道的和你会用到的)
5.iOS进阶——Block
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- iOS 内存 管理
![提示](https://static.bingdoc.com/images/bang_tan.gif)