iOS中的内存管理

本节主要理解:
1.定时器的种类与注意事项(NSTimer循环引用/)
2.内存布局
3.Tagged Pointer
4.引用计数的原理
5.weak引用的原理
6.深拷贝与浅拷贝
7.自动释放池

一.读写安全

1.atomic与noatomic

2.pthead_rwlock

3.dispatch_barrier_async 栅栏函数
多读单写

dispatch_queue_t dispatchQueue = dispatch_queue_create("hyq.queue.next", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, block1_for_reading)  
dispatch_async(queue, block2_for_reading) 

dispatch_async(queue, block_for_writing)

dispatch_async(queue, block3_for_reading)  
dispatch_async(queue, block4_for_reading)

以上可能导致数据混乱
使用栅栏函数

dispatch_async(queue, block1_for_reading)  
dispatch_async(queue, block2_for_reading)

dispatch_barrier_async(queue, block_for_writing)

dispatch_async(queue, block3_for_reading)  
dispatch_async(queue, block4_for_reading) 

dispatch_barrier_async会把队列的运行周期分为这三个过程:

  • 首先等目前追加到并行队列中所有任务都执行完成
  • 开始执行dispatch_barrier_async中的任务这时候即便向并行队列提交任务,也不会执行
  • dispatch_barrier_async中任务执行完成后,并行队列恢复正常。

总的来说,dispatch_barrier_async起到了承上启下的作用。它保证此前的任务都先于自己执行,此后的任务也迟于自己执行。正如barrier的含义一样,它起到一个栅栏或者分水岭的作用。

使用并行队列和diapatch_barrier_async方法,就可以高效的进行数据和文件读写了。

二.Tagged Pointer

■从64bit开始, iOS引入了Tagged Pointer技术,用于优化NSNumber. NSDate. NSString等小对象的存储
■在没有使用Tagged Pointer之前,NSNumber等对象需要动态分配内存、维护引用计数等, NSNumber指针存储的是堆中NSNumber对象的地址值
■ 使用Tagged Pointer之后, NSNumber指针里面存储的数据变成了: Tag + Data ,也就是将数据直接存储在了指针中
当对象指针的最低有效位是1 ,则该指针为Tagged Pointer,当对象指针的最低有效位是0时,为普通OC对象
■当指针不够存储数据时 ,才会使用动态分配内存的方式来存储数据
■objc_ msgSend能识别Tagged Pointer ,比如NSNumber的intValue方法,直接从指针提取数据,节省了以前的调用开销

特点
1.我们也可以在WWDC2013的《Session 404 Advanced in Objective-C》视频中,看到苹果对于Tagged Pointer特点的介绍:
Tagged Pointer专门用来存储小的对象,例如NSNumber和NSDate
2.Tagged Pointer指针的值不再是地址了,而是真正的值。所以,实际上它不再是一个对象了,它只是一个披着对象皮的普通变量而已。所以,它的内存并不存储在堆中,也不需要malloc和free。
3.在内存读取上有着3倍的效率,创建时比以前快106倍。
由此可见,苹果引入Tagged Pointer
,不但减少了64位机器下程序的内存占用,还提高了运行效率。完美地解决了小内存对象在存储和访问效率上的问题。

三.copy和mutableCopy

1.iOS提供了2个拷贝方法
copy,不可变拷贝,产生不可变副本
mutableCopy,可变拷贝,产生可变副本

深拷贝和浅拷贝
深拷贝---内容拷贝,有产生新对象
浅拷贝---指针拷贝,未产生新对象

总结
不可变对象NSString ,NSArray,NSDictionary,copy是浅拷贝,mutableCopy是深拷贝
可变对象NSMutableString,NSMutableArray,NSMutableDictionary,不管copy还是mutableCopy都是深拷贝

图片.png

为什么NSString使用copy修饰,NSMutableString使用strong修饰?
1.当原字符串是NSString时,由于是不可变字符串,所以,不管使用strong还是copy修饰,都是指向原来的对象,copy操作只是做了一次浅拷贝。
2.当源字符串是NSMutableString时,strong只是将源字符串的引用计数加1,而copy则是对原字符串做了次深拷贝,从而生成了一个新的对象,并且copy的对象指向这个新对象。

所以,如果源字符串是NSMutableString的时候,使用strong只会增加引用计数。但是copy会执行一次深拷贝,会造成不必要的内存浪费。而如果原字符串是NSString时,strong和copy效果一样,就不会有这个问题。
但是,我们一般声明NSString时,也不希望它改变,所以一般情况下,建议使用copy,这样可以避免NSMutableString带来的错误。

四.引用计数的存储

在64bit中,引用计数可以直接存储在优化过的isa指针中,也可能存储在SideTable类中

struct SideTable {
  spinlock_t slock;
  RefcountMap refcnts;
  weak_table_ t weak_table;
};

refcnts是一个存放着对象引用计数的散列表

五.autoreleasepool 自动释放池

■自动释放池的主要底层数据结构是 :_ AtAutoreleasePool. AutoreleasePoolPage
■调用了autorelease的对象最终都是通过AutoreleasePoolPage对象来管理的
源码分析

0 clang重写@autoreleasepool

0 objc4源码 : NSObject.mm

class AutoreleasePoolPage
{
  magic_ t const magic;
  id*next; 
  pthread_ _t const thread ; 
  AutoreleasePoolPage * const parent;
  AutoreleasePoolPage *child;
  uint32_ ,t const depth;
  uint32_ .t hiwat;
}
面试题

1.使用CADisplayLink、 NSTimer(基于runloop)有什么注意点 ?
循环引用
CADisplayLink、 NSTimer 会对taget产生强引用,如果target又对他们强引用,就会造成循环引用

此种方式会造成循环引用
self. timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target : self selector :@selector(timerTest) userInfo:nil repeats:YES];

(1)最简单的解决办法如下

_ weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer *_ Nonnull timer) [
  [weakSelf timerTest];
});

(2)或者使用NSProxy,(专门用来做转发,是一个基类,与NSObject并列,方法调用时会省去第一阶段-消息发送阶段,直接进入第三阶段-消息转发阶段)自行了解
不准时
因为依赖于runloop,如果runloop任务过于繁重(如线程中有滚动视图正在滚动,NSTimer会暂停),可能会导致NSTimer不准时,可以使用GCD定时器更加准时

//创建-个定时器
dispatch_ source_ t timer = dispatch_ source_ create (DISPATCH_ SOURCE_ TYPE_ TIMER, 0, 0, queue); 
//没置吋囘(start是几秒后幵始抗行, interval是吋囘囘隔)
dispatch_ source_ ,set_ timer(timer,
dispatch_ time (DISPATCH_ TIME_ NOW, (int64_ t)(start * NSEC_ PER_ SEC)),
(uint64_ t)(interval *NSEC_ PER_ SEC),
0);
//设置回调
dispatch_ source_ ,set_ event_ handler(timer, ^{
));
//启动定时器
dispatch_ resume (timer);

2.介绍下内存的几大区域
地址从低到高布局

图片.png

■代码段: 编译之后的代码
■数据段
0字符串常量:比如NSString *str = @"123"
0已初始化数据:已初始化的全局变量、静态变量等
0未初始化数据:未初始化的全局变量、静态变量等
■堆: 通过alloc、malloc. calloc等动态分配的空间,分配的内存空间地址越来越大
■栈: 函数调用开销,比如局部变量。分配的内存空间地址越来越小

3.讲一下你对iOS内存管理的理解

4.autorelease在什么时机会被释放
① 如果有@autoreleasepool{},所以autoreleasepool里面调用了autorelease方法的对象会在{}结束之后释放。
② 如果没写@autoreleasepool{},由于整个程序没有退出,autoreleasepool里面调用了autorelease方法的对象会在RunLoop休眠之前被释放。

5.方法里有局部对象 ,出了方法后会立即释放吗
会立即释放,因为就相当于在方法的最后加一行release代码。

6.ARC 都帮我们做了什么?
实际上"引用计数式内存管理"的本质在ARC中并没有改变,ARC只是自动的帮助我们处理"引用计数"的相关部分

7.weak指针的实现原理

  • 在64bit中,引用计数可以直接存储在优化过的isa指针中,也可能存储在SideTable类中
struct SideTable {
spinlock_t slock;
RefcountMap refcnts;     refcnts是一个存放着对象引用计数的散列表
weak_table_t weak_table;   弱引用表
};
图片.png

当对象引用计数为0时,会自动调用dealloc方法。
苹果将弱引用都存在一个哈希表中,当对象调用dealloc方法时,系统会取出对象的地址,作为key到哈希表中找到对应的弱引用,并将其销毁掉。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容