當前位置:
首頁 > 最新 > 對待棘手bug,新手與大牛的差距在哪裡?

對待棘手bug,新手與大牛的差距在哪裡?

阿里妹導語:一行代碼引發周邊童鞋的Xcode內存爆炸。作為一名喜歡探究到底的工程師,豈能袖手旁觀?來自高德的濤瀾童鞋,給出了一個樣本式的解決思路。下面就讓我們一起走進「案發現場」。

問題描述:

自上上周起,團隊中陸續有iOS開發抱怨電腦特別卡。有細心的同學發現,因為Xcode佔用了約6-7G內存,而部分mac只有8G內存,所以內存爆滿引起卡頓。

而部分同學的mac是16G內存的,比如我(嘲諷臉),因為內存充足沒感覺到卡。

但這個問題影響團隊的開發效率,所以需要去解決問題。

內存對比:

在沐浴更衣焚香、殺進程、清緩存後,分別拉取相鄰的812版本代碼和816版本代碼分別編譯,得到結論:

812調試時,佔用2G內存

816調試時,佔用6.8G內存

吐槽:

對於這個數據,我們內心是拒絕接受的。有如下2點吐槽:

如果代碼亂申請內存,那麼內存爆掉的應該是模擬器或真機。而不該是Xcode

如果當前版本新增10w行代碼(其實不到),對總代碼量增長不超10%,Xcode內存怎麼可能翻兩翻。

所以我們覺得,這一定是蘋果的鍋,我們不背

但是不管是誰的鍋,肯定是代碼或者配置觸發的,分析還要繼續。

分析方法選擇:

擺在我們面前有2個分析方法:

找代碼:通過二分法,編譯不同日期的版本,找到引發問題的那次提交,確定是哪個改動引起

找內存:分析增大的內存是什麼,根據增大的內容分析問題出在哪。

如果使用方法1,編譯一次代碼需要15分鐘,假設問題是某一行代碼引起的,估計需要找一天。如果是某多行代碼組合影響的問題,時間會更長。而且就算找到代碼,也未必知道原理是什麼。

所以我選擇**方法2**,不行再退到方法1

分析步驟:

我在run的時候發現:

812初次打開代碼內存1G以內,編譯運行時內存2G,關閉Xcode後再打開內存2G

816初次打開代碼內存1G以內,編譯運行時內存6G,關閉Xcode後再打開內存6G

關閉Xcode後再打開,此時Xcode並沒有run,所以推測他在做一件事:讀緩存

緩存文件:

大家都知道,Xcode編譯一個新工程會很慢,但是第二次編譯就很快。那是因為他把編譯結果存到了緩存文件中。第二次編譯只讀文件不編譯自然就快了。

緩存文件存儲在「/Users/你的用戶名/Library/Developer/Xcode/DerivedData」目錄下

812和816版本的緩存文件對比如下:

初步可以看出,緩存文件數量一致,但是大小差距很大。所以下一步就是來找茬:到底誰變大了

經過一番尋找,發現每個類會生成三個文件:

.o文件:二進位對象文件,不多說

.d文件:文本文件,記錄該類依賴的所有文件路徑

.dia文件:未知二進位文件,但是變大的就是它

.dia是有一部分變大了,一部分沒變。嘗試用二進位工具打開讀了一下,有驚喜:

這不就是warning嘛

我的吐槽又來了:

是誰!站出來!**寫了4個G的warning!**

繼續分析:

那具體是什麼導致的warning呢,面對幾千個.dia文件,我內心是崩潰的。

幸好找基友溝通,剛好他做了代碼warning掃描,發現816比812隻是某組代碼多了107個warning,其他組沒變化,而且是nonnull相關warning,並不重要所以沒追究。

我們找到107處warning的代碼,查看提交記錄,就是在大家反饋卡頓之前。貌似就是它了。我們把warning解了,clean重新編譯,問題得解。

問題雖解,但是遺留2個問題:

怎麼就提交了107個warning?

區區107個warning。為啥會導致內存飆升?我們還剩幾百個warning為啥沒問題?

問題1:

引發107個warning的只有一行代碼

對於nonnull相關warning蘋果的潛規則是這樣的:

自Xcode6起提供的新功能,可以申明一個函數的參數是必傳的(nonnull)還是可選的(nullable) ,這會讓代碼更嚴謹,我們是推薦使用的

兼容老代碼:整個頭文件都沒有nonnull/nullable申明的,編譯沒毛病

對新代碼高要求:只要給代碼中添加了一個nonnull/nullable,剩餘的代碼也必須添加,否則其他每個介面就會有warning

所以,這次涉案的代碼是箇舊工具類,有107個函數。新增的一行代碼添加了nonnull。於是產生了107個warning

問題2:

舉個例子,有A B C三個類

A.h有一個warning,其.dia文件中會如下信息:

insert _Nullable if the pointer may be null

insert _Nonnull if the pointer should never be null

A.m文件絕對路徑

A.h文件絕對路徑

A.m文件第幾行引用了A.h,存在warning

warning在A.h的位置

warning描述是:pointer is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)

fix的兩種方法:

總之,一處warning的信息大約是1k

如果B引用了A,則B的.dia文件包含如上所有信息,以及多個B的文件路徑,即B的描述信息超過A

如果C引用了B,而B在頭文件中引用了A,則C的描述信息超過B

所以

在工程上,107warning的文件,dia約130k。

所有直接間接引用的文件數量大概2500,單個文件都超過130k。文件大小約350M。

加上模擬器有2個cpu架構(i386/x86_64),會生成2份文件,緩存中還有個聚合的dgph文件。以及文件在內存中結構化後佔用的內存空間。

所以最終翻了幾倍,達到4G的內存佔用是可以理解的。

結論:

不要忽略warning,特別是頭文件中的warning,會被多處引用導致過大的描述信息

頭文件中盡量不要import頭文件,會造成過度的引用,放大問題。

後續:

818版本已經fix了core中的所有nonnull問題。後續逐步將warning清零

fix後內存佔用如圖

PS:這是蘋果的bug么?我覺得還是自己挖坑把自己埋了。

遇到棘手的bug,你的解決思路是什麼呢?歡迎在評論區留言,一起交流學習。

你可能還喜歡

點擊展開全文

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 阿里技術 的精彩文章:

阿里人打車不給錢?內部自研神器「歡行」首次曝光
2017阿里巴巴技術論壇,本周起將席捲全球四大頂級名校!
下一代高性能資料庫標杆POLARDB 亮相頂會VLDB2017
史無前例開放!阿里內部集群管理系統Sigma混布數據
阿里知識圖譜首次曝光:每天千萬級攔截量,億級別全量智能審核

TAG:阿里技術 |