一、Android內(nèi)存基礎(chǔ)##
物理內(nèi)存與進(jìn)程內(nèi)存
物理內(nèi)存即移動設(shè)備上的RAM
悦屏,當(dāng)啟動一個Android程序時节沦,會啟動一個Dalvik VM
進(jìn)程,系統(tǒng)會給它分配固定的內(nèi)存空間(16M,32M不定)础爬,這塊內(nèi)存空間會映射到RAM上某個區(qū)域甫贯。然后這個Android程序就會運行在這塊空間上。Java里會將這塊空間分成Stack棧內(nèi)存
和Heap堆內(nèi)存
看蚜。stack里存放對象的引用叫搁,heap里存放實際對象數(shù)據(jù)。
在程序運行中會創(chuàng)建對象供炎,如果未合理管理內(nèi)存渴逻,比如不及時回收無效空間就會造成內(nèi)存泄露
,嚴(yán)重的話可能導(dǎo)致使用內(nèi)存超過系統(tǒng)分配內(nèi)存音诫,即內(nèi)存溢出OOM
惨奕,導(dǎo)致程序卡頓甚至直接退出。內(nèi)存泄露(Memory Leak)
Java內(nèi)存泄漏指的是進(jìn)程中某些對象(垃圾對象)已經(jīng)沒有使用價值了竭钝,但是它們卻可以直接或間接地引用到gc roots導(dǎo)致無法被GC回收梨撞。Dalvik VM具備的GC機(jī)制
(垃圾回收機(jī)制)會在內(nèi)存占用過多時自動回收,嚴(yán)重時會造成內(nèi)存溢出OOM香罐。內(nèi)存溢出OOM
當(dāng)應(yīng)用程序申請的java heap空間超過Dalvik VM HeapGrowthLimit時卧波,溢出。
注意:OOM并不代表內(nèi)存不足穴吹,只要申請的heap超過Dalvik VM HeapGrowthLimit
時幽勒,即使內(nèi)存充足也會溢出。效果是能讓較多進(jìn)程常駐內(nèi)存港令。如果RAM不足時系統(tǒng)會做什么啥容?
Android的Memory Killer會殺死優(yōu)先級較低的進(jìn)程,讓高優(yōu)先級進(jìn)程獲取更多內(nèi)存顷霹。Android系統(tǒng)默認(rèn)內(nèi)存回收機(jī)制
-
進(jìn)程優(yōu)先級:
Foreground
進(jìn)程咪惠、Visible
進(jìn)程、Service
進(jìn)程淋淀、Background
進(jìn)程遥昧、Empty
進(jìn)程;
如果用戶按Home鍵返回桌面,那么該app成為Background進(jìn)程朵纷;如果按Back返回炭臭,則成為Empty進(jìn)程
-
ActivityManagerService
直接管理所有進(jìn)程的內(nèi)存資源分配。所有進(jìn)程要申請或釋放內(nèi)存都需要通過ActivityManagerService對象袍辞。 - 垃圾回收不定期執(zhí)行鞋仍。當(dāng)內(nèi)存不夠時就會遍歷heap空間,把垃圾對象刪除搅吁。
- 堆內(nèi)存越大威创,則GC的時間更長
二、優(yōu)化##
-
Bitmap優(yōu)化
Bitmap非常消耗內(nèi)存谎懦,而且在Android中肚豺,讀取bitmap時, 一般分配給虛擬機(jī)的圖片堆棧只有8M界拦,所以經(jīng)常造成OOM問題吸申。所以有必要針對Bitmap的使用作出優(yōu)化:
- 圖片顯示:加載合適尺寸的圖片,比如顯示縮略圖的地方不要加載大圖享甸。
- 圖片回收:使用完bitmap截碴,及時使用
Bitmap.recycle()
回收。
問題:Android不是自身具備垃圾回收機(jī)制嗎枪萄?此處為何要手動回收隐岛。
Bitmap對象不是new生成的,而是通過BitmapFactory生產(chǎn)的瓷翻。而且通過源碼可發(fā)現(xiàn)是通過調(diào)用JNI生成Bitmap對象
(nativeDecodeStream()等方法
)聚凹。所以,加載bitmap到內(nèi)存里包括兩部分齐帚,Dalvik內(nèi)存
和Linux kernel內(nèi)存
妒牙。前者會被虛擬機(jī)自動回收。而后者必須通過recycle()
方法对妄,內(nèi)部調(diào)用nativeRecycle()
讓linux kernel回收湘今。
- 捕獲OOM異常:程序中設(shè)定如果發(fā)生OOM的應(yīng)急處理方式。
- 圖片緩存:
內(nèi)存緩存
剪菱、硬盤緩存
等 - 圖片壓縮:直接使用ImageView顯示Bitmap時會占很多資源摩瞎,尤其當(dāng)圖片較大時容易發(fā)生OOM拴签。可以使用
BitMapFactory.Options
對圖片進(jìn)行壓縮旗们。 - 圖片像素:android默認(rèn)顏色模式為
ARGB_8888
蚓哩,顯示質(zhì)量最高,占用內(nèi)存最大上渴。若要求不高時可采用RGB_565
等模式岸梨。圖片大小:圖片長度*寬度*單位像素所占據(jù)字節(jié)數(shù)
ARGB_4444:每個像素占用2byte內(nèi)存
ARGB_8888:每個像素占用4byte內(nèi)存 (默認(rèn))
RGB_565:每個像素占用2byte內(nèi)存
- 對象引用類型
-
強(qiáng)引用 strong
:Object object=new Object()
稠氮。當(dāng)內(nèi)存不足時曹阔,Java虛擬機(jī)寧愿拋出OOM內(nèi)存溢出異常,也不會輕易回收強(qiáng)引用對象來解決內(nèi)存不足問題隔披; -
軟引用 soft
:只有當(dāng)內(nèi)存達(dá)到某個閾值時才會去回收赃份,常用于緩存
; -
弱引用 weak
:只要被GC線程掃描到了就進(jìn)行回收锹锰; -
虛引用
如果想要避免OOM
發(fā)生芥炭,則使用軟引用
對象,即當(dāng)內(nèi)存快不足時進(jìn)行回收
恃慧;如果想盡快回收某些占用內(nèi)存較大的對象
园蝠,例如bitmap,可以使用弱引用
痢士,能被快速回收彪薛。不過如果要對bitmap作緩存就不要使用弱引用,因為很快就會被GC回收怠蹂,導(dǎo)致緩存失敗
善延。
關(guān)于java對象引用類型,具體可參加本人另一篇文章
- 池 pool
- 對象池:如果某個對象在創(chuàng)建時城侧,需要較大的資源開銷易遣,那么可以將其放入對象池,即將對象保存起來嫌佑,下次需要時直接取出使用豆茫,而不用再次創(chuàng)建對象。當(dāng)然屋摇,維護(hù)對象池也需要一定開銷揩魂,故要衡量。
- 線程池:與對象池差不多炮温,將線程對象放在池中供反復(fù)使用火脉,減少反復(fù)創(chuàng)建線程的開銷。
- 緩存
關(guān)于android緩存機(jī)制,具體可參加本人另一篇文章
參考文章:
Android性能倦挂、內(nèi)存優(yōu)化
Android操作系統(tǒng)的內(nèi)存回收機(jī)制-IBM
Bitmap內(nèi)存優(yōu)化
內(nèi)存優(yōu)化合集