使用Memory Leak進行內存洩漏查找

備註:這是三年前還在做遊戲項目時分享的一篇文章,雖然已經過去三年,但其中所涉及的方法卻一直都在使用,因此再貼出來,希望能幫到一部分程序工程師朋友。

在項目的整個開發過程中一直伴隨著手機客戶端的內存問題,時不時的也會出現一些內存導致的Crash情況,出現Crash的原因可能會有很多,但在IOS設備上很多常常是由於內存吃緊導致的,如果出現內存不夠用而Crash的一個直觀表現是在Iphone 6 plus設備上更容易重現,這是由於6P的內存只有1G,但由於該設備屏幕更大而需要更多的Frame buffer空間,因此在該IOS 設備的內存最為吃緊。

很多內存問題在PC的開發階段就可以暴露出現,這種情況比較容易處理,畢竟PC上工具鏈很豐富,本文要探討的問題是在IOS設備上導致的一些問題,本文也介紹工具是Xcode的Instruments提供的Memory Leaks工具,如圖,由下圖中可以看出Instruments提供了很多工具可供開發使用,其它工具慢慢摸索。

使用Memory Leak進行內存洩漏查找

如何啟動Leaks工具,參考官方文檔[自行搜索吧,頭條不允許放外鏈]

發現問題:

在Xcode中啟動遊戲後,使用內存監控工具查看內存的變化情況,發現當場景Load完成後一段時間內內存是穩定的,然後過段時間內存突然漲了趕來,如下圖所示。出現這個問題第一個反應是去檢查了一下代碼邏輯,打出了一些Log後也沒有發現有哪裡會突然需要分配這麼多的內存,糾結了一會之後突然想來Xcode提供的Memory Profile工具,於是乎有了後面的內容。

使用Memory Leak進行內存洩漏查找

選擇遊戲項目,使用Leaks工具啟動Record功能,在遊戲內跑一下游戲,得到了如下的內存使用時間序列圖,首先從圖中可以看出Neox引擎在啟動遊戲不久之後就出現了內存洩漏(圖中紅色的叉),佔進去看一下吧^^,所幸這些Leaks並非是導致內存暴漲的原因。

使用Memory Leak進行內存洩漏查找

使用Memory Leak進行內存洩漏查找


粗略看了一上內存洩漏的部分,可以看出這些漏洩並不是本次關心的重點,重點是最內存使用圖中最後一次的增長,那麼這一時間段內到底是什麼佔用了內存呢?所幸Instruments給我們提供了查看某一時間段內內存分配的功能,好了,現在就我們把鎖定到第40s左右來看看。

使用Memory Leak進行內存洩漏查找

如圖中藍色部分,時間 大概是39s-42s之間,這段時間內內存增加了大約70M, Allocation Summary部分給出了這段時間內內存的分配情況。從圖中我們可以看到有一個68M的內存分配,那麼這些內存是分配給誰了呢?帶著這個問題,我們一層一層的點進去看看究竟吧。

使用Memory Leak進行內存洩漏查找

進去之後,我們對分配內存的操作進行排下序,會發現有10次的內存分配操作,每次分配了6.6M的內存。也即是說這段時間內NXMemoryFile分配了66M的內存。還好在這一步我們還可以繼續往下深入分析,最終定位到分配內存的那段代碼:

使用Memory Leak進行內存洩漏查找

至此,可以說是找到了內存暴漲的主要原因的線索,由於NXMemoryFile是一個基礎的模塊,其實我們還沒有找到究竟是誰調用了這段代碼,其實到了這一步問題就變得很簡單了,加個斷點,根據call stack來查找問題源頭。ps, 由於Xcode出了點問題,執行斷點時加載不出來了調用棧,這裡面就不貼圖了,棧的源頭是_audio.cpp模塊加載fsb文件。為什麼fsb文件的加載會導致內存的暴漲呢?

FMOD模塊在加載fsb時,以流的方式讀取解壓文件,所以播放FSB格式的音頻文件理論上來說不會導致太多的內存增長,而問題是我們將fsb文件打入了NPK文件內部,因為Fmod模塊沒有辦法直接使用流的方式讀取npk文件,因此為了能夠加載npk內的fsb文件,neox裡面有一個基於內存的文件系統NXMemoryFile,先將文件讀取到內存中,然後fmod才能以文件的形式加載fsb數據,因此也就導致了內存的暴漲。

另外(由於沒看Fmod代碼,這是根據程序運行時的表現猜測的)Fmod在讀fsb時應該是open一個文件,然後持有一個handler,而每一個handler對應一個內存文件,這也就導致了同一份fsb文件在內存中會有多個內存文件。

既然定位到問題是由於將FSB文件打入npk導致的,那麼就嘗試將fsb文件從npk文件中分離出來,下圖是不再將fsb打入npk的客戶端的運行情況,內存的使用情況較先前有了很大的好轉,同時在不同設備上運行一段時間之後,crash的情況也確實變得很少了。

使用Memory Leak進行內存洩漏查找


分享到:


相關文章: