android應(yīng)用程序內(nèi)存優(yōu)化

android應(yīng)用程序內(nèi)存優(yōu)化

對于開發(fā)一個應(yīng)用程序來說膛锭,在前期完成主要功能之后辰妙,后期有一項非常重要的工作康嘉,那就是優(yōu)化應(yīng)用程序的內(nèi)存魂贬。而內(nèi)存優(yōu)化的方向主要是兩個巩割,一個是內(nèi)存溢出,另外一個就是內(nèi)存泄露付燥。

內(nèi)存溢出和內(nèi)存泄露是兩個不同的概念喂分。內(nèi)存溢出指的是內(nèi)存不夠用了,內(nèi)存的使用超過的系統(tǒng)規(guī)定的最大值机蔗。而內(nèi)存泄露指的是由于程序的邏輯錯誤蒲祈,導(dǎo)致一些沒有用的對象無法被垃圾回收器回收而一直占用著內(nèi)存。所以內(nèi)存泄露的堆積可能會造成內(nèi)存溢出萝嘁。而內(nèi)存溢出不一定都是由內(nèi)存泄露引起的梆掸。這兩個概念要搞清楚。

內(nèi)存溢出:

在安卓的應(yīng)用程序中牙言,內(nèi)存溢出主要提要在幾個方面

1酸钦、ListView的顯示

我們在使用ListView的時候,都會給他設(shè)置Adapter咱枉,如果在Adapter中的getView方法 中卑硫,我們沒有復(fù)用convertView,就會造成在滑動ListView的時候蚕断,會為每一個item都 生成一個View對象欢伏,而不管這個item之前是否已經(jīng)生成過View對象。如果來回滑動 的次數(shù)太多的話亿乳,就會造成View生成的數(shù)量太多硝拧,最終會造成內(nèi)存溢出径筏。

如果ListView中的item是包含圖片的,那么障陶,如果在快速滑動的過程中滋恬,我們就去為 item加載圖片,此時非常容易造成內(nèi)存溢出抱究。因為恢氯,在快速滑動的過程中,垃圾回收 器還來不及回收內(nèi)存鼓寺,而新的item又需要新的內(nèi)存來顯示圖片酿雪。所以,在這種情況下侄刽, 一般的做法是監(jiān)聽ListView的滾動狀態(tài)指黎,當(dāng)ListView的滾動狀態(tài)為空閑的情況下,里面 的每一個Item才去加載圖片州丹。

2醋安、加載圖片相關(guān)

a、加載多張圖片

對于加載多張圖片墓毒,我們一般會使用三級緩存來實現(xiàn)圖片的加載吓揪。內(nèi)存緩存、本地 緩存所计、網(wǎng)絡(luò)緩存柠辞。緩存的目的是為了下一次加載速度更快。所以在內(nèi)存中保存著一 定數(shù)量的圖片是有助于下一次圖片顯示的速度主胧。但是叭首,內(nèi)存中不能保存太多的圖片 對象,所以我們使用LRUCache來保存內(nèi)存中的圖片踪栋,并且控制在一定的數(shù)量之內(nèi)焙格。

b、加載單張圖片

這種情況是針對于某一張圖片特別大的情況夷都。如果一張圖片非常非常大眷唉,如果50M, 那么囤官,我只要一去加載它冬阳,那么我的程序肯定就會掛,根本還沒使用到三級緩存應(yīng) 用程序就受不了了党饮。所以肝陪,對于大圖片的顯示需要特殊處理。因為圖片雖然特別大劫谅, 但是這個圖片所需要顯示的控件有可能是很小的见坑。我們可以先把圖片的寬和高得 到嚷掠,再得到這張圖片所需要顯示的控件的寬高捏检,就可以得到圖片和控件的縮放比例 了荞驴。最后,根據(jù)縮放比例贯城,設(shè)置圖片的采樣率熊楼,來減小單張圖片的內(nèi)存占用。

  1. BitmapFactory.Options options = new BitmapFactory.Options();

  2. //只得到圖片的大小能犯,不去加載圖片的內(nèi)容

  3. options.inJustDecodeBounds = true;

  4. Bitmap boundBitmap = BitmapFactory.decodeFile(filePath,options);

  5. int imageWidth = boundBitmap.getWidth();

  6. int imageHeight = boundBitmap.getHeight();

  7. //計算inSampleSize的值 此時可以根據(jù)控件大小和圖片大小來得到縮放比例 這里先寫成2

  8. options.inSampleSize = 2;//圖片寬高都為原來的二分之一鲫骗,即圖片為原來的四分之一

  9. options.inJustDecodeBounds = false;

  10. Bitmap bitmap = BitmapFactory.decodeFile(filePath,options);

內(nèi)存泄露:

內(nèi)存泄露是因為有些對象已經(jīng)沒有用了,但是卻無法被垃圾回收器回收內(nèi)存踩晶,導(dǎo)致這一塊內(nèi)存泄露了执泰。隨著這類問題的堆積,泄露的內(nèi)存越來越大渡蜻,可使用的內(nèi)存越來越小术吝,直到內(nèi)存溢出。

而垃圾回收器無法回收某一些對象茸苇,是因為排苍,這些對象有人引用它了。所以內(nèi)存泄露的本質(zhì)就是学密,生命周期短的對象一直被生命周期長的對象引用淘衙,導(dǎo)致生命周期短的對象無法被垃圾回收器回收。

在安卓的應(yīng)用程序當(dāng)中腻暮,內(nèi)存泄露主要體現(xiàn)在幾個方面

1彤守、注冊了之后忘了反注冊

BraodcastReceiver,ContentObserver哭靖,F(xiàn)ileObserver在Activity onDestory或者某類聲明  周期結(jié)束之后一定要unregister掉遗增,否則這個Activity會被system強(qiáng)引用,不會被內(nèi)存  回收款青。對于觀察者模式的寫法做修,在注冊某一些觀察者的時候,要既得在適當(dāng)?shù)臅r候抡草,把  對應(yīng)的觀察者從觀察者列表中移除饰及。否則存儲觀察者的集合列表會不斷的擴(kuò)大。

2康震、****資源對象沒關(guān)閉

資源性對象比如Cursor燎含,F(xiàn)ile文件等,在內(nèi)部的實現(xiàn)機(jī)制中都用了一些緩沖腿短,所以在不 使用的時候這些資源對象的時候應(yīng)該及時關(guān)閉它們屏箍,這樣绘梦,他們的緩沖區(qū)域才能被既時 候回收。它們的緩沖不僅存在于Java虛擬機(jī)內(nèi)赴魁,還存在于Java虛擬機(jī)外卸奉。如果我們僅 僅是把它的引用設(shè)置為null,而不關(guān)閉它們,往往會造成內(nèi)存泄露颖御。我們需要在這些對象 不使用的情況下榄棵,立即調(diào)用close方法,然后再設(shè)置為null潘拱。

3疹鳄、****activity被集合引用導(dǎo)致activity不能釋放

一般我們在應(yīng)用程序中,做一個退出應(yīng)用程序的功能芦岂。當(dāng)點(diǎn)擊退出按鈕的時候瘪弓,此時應(yīng) 該把這個應(yīng)用中所有activity都finish掉,這樣就可以退出這個應(yīng)用了禽最。所以腺怯,我們需 要在每一個activity中的onCreate方法里,將當(dāng)前啟動的activity保存在某一個集合列 表里面弛随。這個集合列表可以存在于Application中的一個ArrayList瓢喉。此時,如果在activity 中的onDestory沒有將當(dāng)前的activity對象從集合列表中移除的話舀透,那么就會造成activity 雖然退出了栓票,但是這個activity的對象依然無法被系統(tǒng)回收,因為有一個集合一直引用 著這個activity對象愕够。所以一定要記得在onDestory方法中把當(dāng)前的activity對象從集合 列表中移除走贪。

4、****Bitmap對象不在使用時調(diào)用recycle()釋放內(nèi)存

Bitmap非常的耗內(nèi)存惑芭。 多使用幾個Bitmap很可能一下子就會超過Java堆的限制坠狡。因此,在 用完Bitmap時遂跟,要 及時的recycle掉逃沿。recycle并不能立即將Bitmap的內(nèi)存釋放,但是會在垃 圾回收器下一個工作的時機(jī)將這個bitmap回收幻锁。

解決方案

無論是內(nèi)存泄露還是內(nèi)存溢出凯亮,最終的后果基本上是一致的,那就是造成應(yīng)用程序強(qiáng)行關(guān)閉哄尔。在應(yīng)用程序的功能開發(fā)完之后假消,怎么樣才能確定應(yīng)用程序有沒有內(nèi)存的問題呢?又怎樣來確定到底是哪一塊代碼出的問題呢岭接?接下來我們就來說說關(guān)于內(nèi)存問題的解決方案富拗。

1臼予、使用monkey工具

因為有些內(nèi)存問題藏的比較深,要長期使用才能出現(xiàn)異常啃沪。所以可以使用monKey工具 來對我們的應(yīng)用程序進(jìn)行壓力測試粘拾。

模擬200000次用戶操作的參考命令: adb shell monkey -s 23 -p cn.itcast.XXX(所測試的 包) --ignore-crashes --ignore-timeouts -v -v -v 200000 > D:\文件名.log

回車之后,我們所需要測試的應(yīng)用程序就啟動了谅阿,并且還有不斷觸摸事件被促發(fā)半哟,程序 生成的log會保存在D目錄下酬滤。

2签餐、捕獲OOM異常

自定義Application并讓它實現(xiàn)UncaughtExceptionHandler 接口,在onCreate方法中讓 自己成為系統(tǒng)的默認(rèn)異常處理機(jī)制盯串。Thread.setDefaultUncaughtExceptionHandler(this);

這樣子設(shè)置之后氯檐,如果應(yīng)用程序出現(xiàn)異常,就會調(diào)用Application中的uncaughtException 方法体捏。我們就在這個方法中判斷異常是否為OOM異常冠摄。如果是OOM異常,就將內(nèi)存 快照導(dǎo)到sd卡中去几缭。

image.png

這樣子之后河泳,我們就可以在sd卡上找到發(fā)生異常時的內(nèi)存快照

3、分析內(nèi)存快照

使用MAT工具對內(nèi)存快照文件進(jìn)行分析年栓。

在使用MAT工具打開內(nèi)存快照文件的時候拆挥,需要先將文件進(jìn)行轉(zhuǎn)換一下。因為MAT只 能識別JAVA的內(nèi)存快照某抓,而我們安卓的內(nèi)存快照和JAVA的內(nèi)存快照有點(diǎn)不太一樣纸兔,所 以需要進(jìn)行轉(zhuǎn)化。

例如:

image.png

接下來就是使用MAT工具打開轉(zhuǎn)化過后的內(nèi)存快照文件了否副。通過MAT工具可以看出這 個內(nèi)存快照有幾個對象汉矿,對象之間的引用關(guān)系是怎樣的。這樣對我們定位內(nèi)存問題非常 有幫助备禀。

一般在應(yīng)用程序開發(fā)的后期會使用這三個步驟來增強(qiáng)應(yīng)用程序的健壯性洲拇。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市曲尸,隨后出現(xiàn)的幾起案子赋续,更是在濱河造成了極大的恐慌,老刑警劉巖队腐,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚕捉,死亡現(xiàn)場離奇詭異,居然都是意外死亡柴淘,警方通過查閱死者的電腦和手機(jī)迫淹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門秘通,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人敛熬,你說我怎么就攤上這事肺稀。” “怎么了应民?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵话原,是天一觀的道長。 經(jīng)常有香客問我诲锹,道長繁仁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任归园,我火速辦了婚禮黄虱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘庸诱。我一直安慰自己捻浦,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布桥爽。 她就那樣靜靜地躺著朱灿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪钠四。 梳的紋絲不亂的頭發(fā)上盗扒,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天,我揣著相機(jī)與錄音形导,去河邊找鬼环疼。 笑死,一個胖子當(dāng)著我的面吹牛朵耕,可吹牛的內(nèi)容都是我干的炫隶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼阎曹,長吁一口氣:“原來是場噩夢啊……” “哼伪阶!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起处嫌,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤栅贴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后熏迹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體檐薯,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了坛缕。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片墓猎。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖赚楚,靈堂內(nèi)的尸體忽然破棺而出毙沾,到底是詐尸還是另有隱情,我是刑警寧澤宠页,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布左胞,位于F島的核電站,受9級特大地震影響举户,放射性物質(zhì)發(fā)生泄漏烤宙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一敛摘、第九天 我趴在偏房一處隱蔽的房頂上張望门烂。 院中可真熱鬧乳愉,春花似錦兄淫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至坡脐,卻和暖如春泄私,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背备闲。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工晌端, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人恬砂。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓咧纠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親泻骤。 傳聞我的和親對象是個殘疾皇子漆羔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355