最近我在看“ I am Zombie”赖淤,所以我就來(lái)看看iOS的這個(gè)工具啦蜀漆,哈哈,一大群Zombies正在逼近T酆怠H范绷耍!
什么是Zombie
是的,打開(kāi)instruments之后其實(shí)會(huì)看到一個(gè)圖標(biāo)鲜侥,這個(gè)圖標(biāo)多么讓人激動(dòng)肮邮肌!描函!哈哈
我們順便來(lái)看下官方文檔的說(shuō)法
The Zombies template causes persistent memory growth because it changes your environment so that deallocated objects are never technically deallocated. This is expected behavior, but it means that aside from zombie flags and memory address histories, any other statistics provided by the Allocations instrument should be ignored. You also shouldn’t add the Leaks instrument to the Zombies template, as it will produce inaccurate results. For iOS apps, use the Zombies template with the iOS Simulator, rather than a physical device.
不過(guò)我在嘗試的時(shí)候其實(shí)還沒(méi)有看到這段文字崎苗,所以我也是用了真機(jī),不過(guò)卡的是一塌糊涂舀寓。我查了網(wǎng)上大部分的資料胆数,有的會(huì)說(shuō)Zombie不支持真機(jī),其實(shí)就是rather than互墓,你懂的必尼,不過(guò)的確不建議用,本身調(diào)查的問(wèn)題在這個(gè)環(huán)境上關(guān)系不大篡撵,更多的純粹就是代碼上的問(wèn)題判莉。
用白話文來(lái)解釋下吧,取名Zombie其實(shí)是有道理的酸休,在iOS中我們經(jīng)常會(huì)有一些對(duì)象(雖然iOS在5.0之后引入了ARC)會(huì)手動(dòng)或者自動(dòng)被ARC銷毀掉骂租,但是我們的程序可能并不知道對(duì)象不在了,還可能去調(diào)用它斑司,導(dǎo)致了EXC_BAD_ACCESS的錯(cuò)誤渗饮。當(dāng)然,如果程序簡(jiǎn)單的話宿刮,很容易能夠排查出來(lái)互站,但是我們項(xiàng)目中大多是很復(fù)雜的,排查起來(lái)就有一定的困難僵缺。這個(gè)時(shí)候就會(huì)去使用Zombie工具來(lái)做輔助胡桃。注意,在專項(xiàng)里面工具都是輔助的磕潮,沒(méi)有一個(gè)工具是可以說(shuō)你做了1翠胰,2,3自脯,4步驟就知道問(wèn)題在哪兒之景,幾乎沒(méi)有,所以專項(xiàng)并不是很多人想的那么簡(jiǎn)單的膏潮。開(kāi)啟Zombie有兩種方式锻狗,一種是通過(guò)instruments來(lái)直接使用,網(wǎng)上都會(huì)很推薦這種做法,還有一種就是在如下設(shè)置中去運(yùn)行Zombie默認(rèn)就打包在app中轻纪,這種方法很不可取油额,因?yàn)橐坏┰谏暇€之前忘記關(guān)閉這個(gè)選項(xiàng)的話可是毀滅性的。
簡(jiǎn)單來(lái)講刻帚,Zombie會(huì)去取代那些已經(jīng)被銷毀的對(duì)象潦嘶,讓這些對(duì)象并不是null的存在,而是僵尸的存在我擂。這樣做的好處在于能夠給予我們更多的info來(lái)定位問(wèn)題衬以,而不好的話也是顯而易見(jiàn)的,上面官方的描述也寫(xiě)的很清楚校摩,一旦開(kāi)啟full on Zombie mode(這個(gè)詞來(lái)自于美劇I am Zombie)看峻,那么你的應(yīng)用的內(nèi)存會(huì)不停的飆升,因?yàn)槟愕膶?duì)象永遠(yuǎn)都不會(huì)銷毀衙吩,直到app crash互妓。所以這里大家要注意危險(xiǎn)性。
什么是ARC
這其實(shí)要詳細(xì)了解坤塞,大家可以自行Google冯勉,這里我就隨便截圖一段,科普一下
Automatic Reference Counting摹芙,自動(dòng)引用計(jì)數(shù)灼狰,即ARC,可以說(shuō)是WWDC2011和iOS5所引入的最大的變革和最激動(dòng)人心的變化浮禾。ARC是新的LLVM 3.0編譯器的一項(xiàng)特性交胚,使用ARC,可以說(shuō)一舉解決了廣大iOS開(kāi)發(fā)者所憎恨的手動(dòng)內(nèi)存管理的麻煩盈电。
在工程中使用ARC非常簡(jiǎn)單:只需要像往常那樣編寫(xiě)代碼蝴簇,只不過(guò)永遠(yuǎn)不寫(xiě)retain,release和autorelease三個(gè)關(guān)鍵字就好~這是ARC的基本原則。當(dāng)ARC開(kāi)啟時(shí)匆帚,編譯器將自動(dòng)在代碼合適的地方插入retain, release和autorelease熬词,而作為開(kāi)發(fā)者,完全不需要擔(dān)心編譯器會(huì)做錯(cuò)(除非開(kāi)發(fā)者自己錯(cuò)用ARC了)吸重。好了互拾,ARC相當(dāng)簡(jiǎn)單吧~到此為止,本教程結(jié)束嚎幸。
什么是EXC_BAD_ACCESS
90%的錯(cuò)誤來(lái)源在于對(duì)一個(gè)已經(jīng)釋放的對(duì)象進(jìn)行release操作颜矿。不過(guò)的確看到這個(gè)缺陷,項(xiàng)目一復(fù)雜鞭铆,很難去定位。
案例
所有說(shuō)專項(xiàng)的沒(méi)有案例都是耍流氓,真心覺(jué)得這是真理车遂。
我千辛萬(wàn)苦的隨便找了一個(gè)案例封断,然后發(fā)現(xiàn)啟動(dòng)之后就crash,我心都碎了舶担,那么偶爾我們也要來(lái)修一次bug不是坡疼?基本上我縮小了范圍,錯(cuò)誤代碼如下:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the navigation controller's view to the window and display.
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
錯(cuò)誤信息如
2015-09-25 21:32:05.749 Zombie[24745:854954] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Application windows are expected to have a root view controller at the end of application launch'
反正我是不懂衣陶,經(jīng)過(guò)了Google之后柄瑰,我發(fā)現(xiàn)是iOS本身API的改變,應(yīng)該如下修改
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the navigation controller's view to the window and display.
- [self.window addSubview:navigationController.view];
+ [self.window setRootViewController:navigationController];
[self.window makeKeyAndVisible];
return YES;
}
好了剪况,一切就妥妥的了教沾。經(jīng)過(guò)一系列的操作之后我們可以看到:
類似的錯(cuò)誤,然后可以看到如下的錯(cuò)誤時(shí)候的信息
好了译断,接著讓我們開(kāi)啟full on Zombie Mode吧授翻。使用Zombie來(lái)啟動(dòng)我們的應(yīng)用,按照同樣的操作孙咪,我們可以看到crash的時(shí)候會(huì)出現(xiàn)一個(gè)小的紫色旗子堪唐,上面的信息告訴我們,明顯是一個(gè)消息發(fā)給一個(gè)已經(jīng)被干掉的對(duì)象翎蹈。
我們可以點(diǎn)擊Zombie這條額外信息的右邊的小箭頭淮菠,可以看到如下的信息
這里我們可以看到有AutoRelease指向了我們的Zombie project,我們點(diǎn)擊進(jìn)入可以看到:
這里的lastString是一個(gè)AutoRelease的變量荤堪,而_lastString是指向這個(gè)字符串的指針合陵,所以當(dāng)被自動(dòng)釋放的時(shí)候,_lastString就指向了一個(gè)null逞力,從而就變成了我們最早看到的那個(gè)錯(cuò)誤曙寡。
至此,我們其實(shí)只要將lastString手動(dòng)的保留一下retain寇荧,這個(gè)程序就不會(huì)再crash了举庶。不過(guò)這個(gè)程序的確還是存在很多的內(nèi)存泄漏,作為之后的案例還是很不錯(cuò)的揩抡。