android内存不足,Android OutOfMemoryError:内存不足问题的排查与解决
程序出現(xiàn)了內(nèi)存不足的問題。經(jīng)過DDMS的監(jiān)控,發(fā)現(xiàn)作為一個apk才十來M的程序,竟然把系統(tǒng)最多分配的128M內(nèi)存占光光。經(jīng)過一系列曲折的過程,基本查明了所有的問題所在。
內(nèi)存泄露
為了便于理解,這里把一個對象里引用另一個對象的現(xiàn)象,稱為“持有”;把垃圾回收器及其動作,統(tǒng)稱為GC;如果A對象持有B對象,B對象又持有C對象,形成一個鏈條樣結(jié)構(gòu),稱為一個持有鏈。
GC的一個基本方法是“標(biāo)記-清掃”,就是從堆棧和靜態(tài)存儲區(qū)出發(fā),遍歷所有的對象和它們所持有的對象,形成一個樹形結(jié)構(gòu)(稱為引用樹),對于被遍歷到的對象進(jìn)行標(biāo)記,最后釋放掉那些沒有被標(biāo)記的對象。
堆棧和靜態(tài)存儲區(qū)里的對象,在這里通常被稱為GC Roots。根據(jù)這篇文章,靜態(tài)存儲區(qū)存保存的對象通常有以下幾類:
Class - 由系統(tǒng)類加載器(system class loader)加載的對象
Thread - 活著的線程
Stack Local - Java方法的local變量或參數(shù)
JNI Local - JNI方法的local變量或參數(shù)
JNI Global - 全局JNI引用
Monitor Used - 用于同步的監(jiān)控對象
Held by JVM - 用于JVM特殊目的由GC保留的對象,但實際上這個與JVM的實現(xiàn)是有關(guān)的。
如果一個對象,直接或者間接地被上面這些GC Roots所持有的話,即使已經(jīng)沒有用了,也不會被GC清理掉,內(nèi)存泄漏就這樣產(chǎn)生了。
這種不合理的持有鏈通常有以下這些類型:
Android特有的隱式持有
與Java不同地,Android中會發(fā)生一些隱式的持有。比如,在一個Activity里,通過調(diào)用findById()、getDrawable()等函數(shù)的方式,獲取到一個畫面元素,那么這個元素就會隱式地持有當(dāng)前的Activity作為mContext。一般情況下,這樣并沒有問題;但如果這個元素是作為靜態(tài)對象定義在Activity的類中,就不會被釋放,從而導(dǎo)致Activity也不能釋放。
Android內(nèi)存泄漏排查工具:Leak Canary
這個工具引用到項目中后,在程序運行過程中,如果出現(xiàn)了內(nèi)存泄露,就會自動提示在手機屏幕上;點擊通知區(qū)域中的相應(yīng)條目,就可以看到泄露的Activity和相應(yīng)的持有鏈,對于分析內(nèi)存泄漏十分有效。
需要注意的是,因為需要以DebugCompile的方式編譯到程序中去,所以這個庫只有在Gradle構(gòu)建的項目中才可以引用,基于Ant的項目就請先遷移到Gradle上去吧。
不合理的圖片-DPI對應(yīng)
現(xiàn)在手機屏幕的效果越來越細(xì)膩,除了顏色越來越鮮艷之外,像素密度——DPI也越來越高(所謂的視網(wǎng)膜屏)。Android為了正確處理不同DPI下圖片顯示的效果,規(guī)定了程序的圖片按不同的DPI設(shè)計多套,分別分別存放在各自的目錄下的方法。在程序運行時,由系統(tǒng)挑選最合適的目錄進(jìn)行顯示。
按DPI從小到大,這些目錄分別為: drawable-ldpi(低)→ drawable-mdpi(中)→ drawable-hdpi(高)→ drawable-xhdpi(超高)→ drawable-xxhdpi(超超高)→ ……
DPI并不等同于屏幕分辨率,也不等同于屏幕尺寸,它們之間的關(guān)系簡單來說就是: DPI×屏幕尺寸=分辨率。
但是由于這幾年的手機尺寸大部分都在5寸上下(需要兩只手抱著打電話的那種奇葩沒法說),所以剩下的兩個變量,DPI和分辨率之間是有一個粗略的對應(yīng)關(guān)系的,如下表:
在設(shè)計圖片的時候,如果能按照上面這幾種尺寸分別設(shè)計好圖片,一般來說在分辨率上就不會有太大的偏差。
以上內(nèi)容其實有點跑題了,那么圖片DPI和內(nèi)存占用之間有什么關(guān)系呢?
非常有關(guān)系!經(jīng)過dump heap,找到一些占用內(nèi)存比較兇狠(5M起)的BitMap對象,對其中mData對象進(jìn)行保存,并用 XXXXXXX打開(顯示出來),找到這張圖片后大吃一驚:一個10KB左右的圖片,在內(nèi)存中竟然占到7MB!
上面這一系列操作的詳細(xì)方法點這里XXXXXXXXXX和這里XXXXXXXXX(待補充)。 順便吐槽下,IntelliJ比起Android Studio要先進(jìn)好幾個版本,但是只要程序稍稍多占用點內(nèi)存的時候,用IntelliJ dump heap完全不行,直接卡死,耽誤了好長時間,最后換了Android才完成。
言歸正傳,為什么一張圖片會占用這么大的內(nèi)存空間?有些老舊的項目,最初不注意DPI的問題,甚至就直接把所有的圖片放在drawable下。這種情況下,其實是當(dāng)作mdpi來處理的。但現(xiàn)在的手機屏幕,動輒都是xhdpi起,和mdpi之間相差兩三個檔次。
總結(jié)
以上是生活随笔為你收集整理的android内存不足,Android OutOfMemoryError:内存不足问题的排查与解决的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html5下拉列表默认值,element
- 下一篇: android自定义相机预览尺寸,相机在