一使用CADisplayLink、NSTimer有什么注意點(diǎn)?
- 循環(huán)引用
二 介紹下內(nèi)存的幾大區(qū)域
代碼段:編譯之后的代碼
-
數(shù)據(jù)段
- 字符串常量:比如NSString *str = @"123"
- 已初始化數(shù)據(jù):已初始化的全局變量、靜態(tài)變量等
- 未初始化數(shù)據(jù):未初始化的全局變量、靜態(tài)變量等
棧:函數(shù)調(diào)用開(kāi)銷(xiāo),比如局部變量。分配的內(nèi)存空間地址越來(lái)越小
堆:通過(guò)alloc、malloc、calloc等動(dòng)態(tài)分配的空間,分配的內(nèi)存空間地址越來(lái)越大
三 講一下你對(duì) iOS 內(nèi)存管理的理解
四 ARC 都幫我們做了什么?
- LLVM + Runtime
首先利用LLVM,幫我們自動(dòng)生成release,retain,autorelease代碼
需要runtime運(yùn)行時(shí)做一些事情
即ARC時(shí)LLVM編譯器和Runtime系統(tǒng)相互協(xié)作的一個(gè)結(jié)果
五 weak指針的實(shí)現(xiàn)原理
將弱引用存儲(chǔ)到一個(gè)哈希表里,當(dāng)對(duì)象要銷(xiāo)毀時(shí),就會(huì)取出當(dāng)前對(duì)象的弱引用表,將該表存儲(chǔ)的弱引用都給清除掉
六 autorelease對(duì)象在什么時(shí)機(jī)會(huì)被調(diào)用release
iOS在主線程的Runloop中注冊(cè)了2個(gè)Observer
- 第1個(gè)Observer監(jiān)聽(tīng)了
kCFRunLoopEntry事件,會(huì)調(diào)用objc_autoreleasePoolPush() - 第2個(gè)Observer
- 監(jiān)聽(tīng)了
kCFRunLoopBeforeWaiting事件,會(huì)調(diào)用objc_autoreleasePoolPop()、objc_autoreleasePoolPush() - 監(jiān)聽(tīng)了
kCFRunLoopBeforeExit事件,會(huì)調(diào)用objc_autoreleasePoolPop()
- 監(jiān)聽(tīng)了
代碼例子如下
- (void)viewDidLoad {
[super viewDidLoad];
Person *person = [[Person alloc] init];
NSLog(@"%s", __func__);
}
這個(gè)Person什么時(shí)候調(diào)用release,是由RunLoop來(lái)控制的
它可能是在某次RunLoop循環(huán)中,RunLoop休眠之前調(diào)用了release
Person *person = [[[Person alloc] init] autorelease];
6.1 包含在@autoreleasepool中,則在pop的時(shí)候,即@@autoreleasepool作用域結(jié)束的時(shí)候銷(xiāo)毀。
七 方法里有局部對(duì)象, 出了方法后會(huì)立即釋放嗎
- MRC環(huán)境下
不一定,是在當(dāng)前runloop循環(huán)中,即將進(jìn)入休眠時(shí)釋放 - ARC環(huán)境下
馬上釋放,只要出了作用域就釋放
八 思考以下2段代碼能發(fā)生什么事?有什么區(qū)別?
@property(nonatomic,strong)NSString *name;
// @property(nonatomic,copy)NSString *name;
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i < 1000; i++) {
dispatch_async(queue, ^{
// 加鎖
self.name = [NSString stringWithFormat:@"abcdefghijk"];
// 解鎖
});
}
運(yùn)行結(jié)果

- 分析
因?yàn)榻oself.name賦值,實(shí)際上是調(diào)用其set方法
- (void)setName:(NSString *)name {
if (_name != name) {
[_name release];
_name = [name retain];
}
}
在set方法內(nèi)部,會(huì)先執(zhí)行release操作,然后再執(zhí)行retain操作,如果是多個(gè)線程同時(shí)執(zhí)行set方法,則會(huì)造成釋放2次的情況,所有導(dǎo)致壞內(nèi)存訪問(wèn)。
代碼二
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
for (int i = 0; i < 1000; i++) {
dispatch_async(queue, ^{
self.name = [NSString stringWithFormat:@"abc"];
});
}
執(zhí)行結(jié)果:正常訪問(wèn)沒(méi)有奔潰報(bào)錯(cuò)。
- 分析上面兩個(gè)為什么會(huì)出現(xiàn)不同的執(zhí)行結(jié)果
NSString *str1 = [NSString stringWithFormat:@"abc"];
NSString *str2 = [NSString stringWithFormat:@"123abc11111111"];
NSLog(@"%@ %@", [str1 class], [str2 class]);
NSLog(@"%p %p", str1,str2);
運(yùn)行結(jié)果

因?yàn)橐粋€(gè)是
NSTaggedPointerString,一個(gè)是__NSCFString
本文參考:
路飛_Luck (http://www.itdecent.cn/p/07f7b96bb03f)
以及借鑒MJ的教程視頻
非常感謝.