內(nèi)存溢出與內(nèi)存泄露
一、定義
- 內(nèi)存溢出: 即為out of memory, 當(dāng)你要求分配的內(nèi)存超過(guò)了系統(tǒng)給你的內(nèi)存時(shí), 系統(tǒng)就會(huì)拋出out of memory的異常(每個(gè)Android能用的內(nèi)存是有限的)
比如: 當(dāng)前應(yīng)用只剩下4M的空間可用, 但你卻加載得到一個(gè)需要占用5M空間的圖片Bitmap對(duì)象, 就會(huì)拋出溢出的異常
- 內(nèi)存泄露: 即為memory leak, 一個(gè)對(duì)象被創(chuàng)建后, 你不再使用它了, 但因?yàn)槟撤N原因它又沒(méi)有成為垃圾對(duì)象, 這塊內(nèi)存不能再被分配置使用.
比如: 查詢數(shù)據(jù)庫(kù)得到的cursor對(duì)象在使用完后沒(méi)有關(guān)閉, Activity中使用Handler發(fā)延遲消息, 但退出前不移除未處理的消息
- 內(nèi)存泄露不多時(shí)沒(méi)有太大影響, 但積累得多了就會(huì)導(dǎo)致應(yīng)用運(yùn)動(dòng)緩慢, 到最后就會(huì)內(nèi)存溢出.
二、內(nèi)存泄漏的分類
- 常發(fā)性內(nèi)存泄漏: 發(fā)生內(nèi)存泄漏的代碼會(huì)被多次執(zhí)行到,每次被執(zhí)行的時(shí)候都會(huì)導(dǎo)致一塊內(nèi)存泄漏
- 偶發(fā)性內(nèi)存泄漏: 發(fā)生內(nèi)存泄漏的代碼只有在某些特定環(huán)境或操作過(guò)程下才會(huì)發(fā)生。常發(fā)性和偶發(fā)性是相對(duì)的。對(duì)于特定的環(huán)境,偶發(fā)性的也許就變成了常發(fā)性的
- 一次性內(nèi)存泄漏: 發(fā)生內(nèi)存泄漏的代碼只會(huì)被執(zhí)行一次,或者由于算法上的缺陷,導(dǎo)致總會(huì)有一塊僅且一塊內(nèi)存發(fā)生泄漏
???說(shuō)明: 危害性大小順序?yàn)? ?1)>2)>3)
三、造成內(nèi)存泄露的幾種場(chǎng)景
- 長(zhǎng)生命周期的對(duì)象持有短生命周期對(duì)象的引用: ?Activity中使用Handler
- 資源數(shù)據(jù)連接相關(guān)對(duì)象不關(guān)閉: cusor, stream, connection
- HashSet中的對(duì)象或HashMap中的Key對(duì)象, 基內(nèi)部與hash值相關(guān)的屬性被修改
- 一些對(duì)象產(chǎn)生后不會(huì)自動(dòng)釋放或需要完全執(zhí)行完了才釋放. 比如: Bitmap, Thread, AsyncTask
四、避免內(nèi)存泄露
- 盡早釋放無(wú)用對(duì)象的引用
- 使用字符串處理,避免使用String,應(yīng)大量使用StringBuffer,每一個(gè)String對(duì)象都得獨(dú)立占用內(nèi)存一塊區(qū)域
- 盡量少用靜態(tài)變量,因?yàn)殪o態(tài)變量存放在永久代(方法區(qū)),永久代基本不參與垃圾回收
- 避免在循環(huán)中創(chuàng)建對(duì)象
五、造成內(nèi)存溢出的的場(chǎng)景
- 申請(qǐng)了太多的對(duì)象. 比如: 使用ListView時(shí), 不復(fù)用convertView, 當(dāng)數(shù)據(jù)項(xiàng)多時(shí)就會(huì)出現(xiàn)內(nèi)存溢出
- 創(chuàng)建的對(duì)象內(nèi)存太大. 比如: 不經(jīng)過(guò)壓縮直接加載大圖片文件
- 內(nèi)存泄露積累一定的時(shí)間后就可能出現(xiàn)
六、避免內(nèi)存溢出
- 通過(guò)復(fù)用對(duì)象的方式, 減少產(chǎn)生的對(duì)象
- 大對(duì)象需要先壓縮后創(chuàng)建
- 避免或減少內(nèi)存泄露的情況