您好,登錄后才能下訂單哦!
這篇文章主要介紹了Android內(nèi)存優(yōu)化策略的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
內(nèi)存優(yōu)化一般從兩個方向著手優(yōu)化,一方面就是上篇博客寫的防止內(nèi)存泄漏,避免不必要的內(nèi)存資源浪費;另一方面就是APP中大對象的優(yōu)化,減小大對象占用的內(nèi)存。
這里直接看上篇博客就行:
詳解Android內(nèi)存泄露及優(yōu)化方案
圖片加載算是內(nèi)存占用的罪魁禍?zhǔn)?,而且也是最常見的,所以?yōu)化bitmap的占用內(nèi)存是很關(guān)鍵的。
Bitmap的內(nèi)存計算公式如下:
Bitmap占用內(nèi)存 = 分辨率 * 單個像素點的內(nèi)存
比如說一個 1920 * 1080 的圖片,它所占用的內(nèi)存就是1920 * 1080 * 單個像素點內(nèi)存。因此,對于Bitmap的優(yōu)化就可以從分辨率和單個像素點兩個方面來進行優(yōu)化。
通常APP加載一張圖片時候,ImageView的大小是確定的,比如一個ImageView的大小設(shè)置為 100 * 100 ,但是被加載的Bitmap的分辨率是 200 * 200,那么就可以通過采樣壓縮將該 ‘Bitmap' 的分辨率壓縮到 ‘100 * 100'。通過這一壓縮操作可以直接減少4倍的內(nèi)存大小。代碼如下:
val options = BitmapFactory.Options() options.inSampleSize = 2 // 設(shè)置采樣率為2,則會每兩個像素點采一個像素,最終分辨率寬高變?yōu)樵瓉淼?nbsp;1/2 val bitmap = BitmapFactory.decodeResource(resources, R.drawable.image, options)
計算機中的圖像一般都是由 紅、綠、藍 三個通道加上一個透明通道組成的,因此一個像素點也是由紅、綠、藍,以及一個透明通道組成,對應(yīng)到內(nèi)存就是通過byte來表示,比如用2個 byte 來存儲一個像素點,那么每個通道就占用 4 bit 的內(nèi)存,而如果用 4 個 byte 來存儲一個像素點,那么每個通道就占用 1 個byte。4 字節(jié)的像素點,相比2字節(jié)的像素點可以表示的色彩會更加豐富,因此四字節(jié)的像素點組成的圖像質(zhì)量也更加清晰。(一個Byte由8 bits組成,是數(shù)據(jù)存儲的基礎(chǔ)單位,1Byte又稱為一個字節(jié))
在 Android 的 Bitmap 中單個像素點占用的內(nèi)存與 Bitmap 的 inPreferredConfig 參數(shù)配置有關(guān)系,代碼設(shè)置如下:
final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true;//只解析圖片邊沿,獲取寬高 options.inPreferredConfig = Bitmap.Config.RGB_565; BitmapFactory.decodeFile(filePath, options); // 計算縮放比 options.inSampleSize = calculateInSampleSize(options, desWidth, desHeight); // 完整解析圖片返回bitmap options.inJustDecodeBounds = false; Bitmap bm = BitmapFactory.decodeFile(filePath, options);
options.inPreferredConfig = Bitmap.Config.RGB_565;設(shè)置的參數(shù)如下表:
Config設(shè)置 | 占用內(nèi)存(byte) | 備注 |
---|---|---|
ALPH_8 | 1 | 只包含一個透明通道,透明通道占用 8bit,即 1byte |
RGB_565 | 2 | 包含R/G/B三個顏色通道,不包含透明通道,三個通道占用的內(nèi)存分別為5bit/6bit/5bit |
ARGB_4444 | 2 | 已廢棄,包含A/R/G/B四個顏色通道,每個通道占用4bit |
ARGB_8888 | 4 | 24位真彩色,Android默認(rèn)配置,每個通道占用 8bit |
RGBA_F16 | 8 | Android 8.0 新增,每個通道占用16bit,即兩個字節(jié) |
在Android系統(tǒng)中 Bitmap 的默認(rèn)色彩模式為 ARGB_8888, 即每個像素占用了4byte,那么在默認(rèn)情況下,一張分辨率為1920 * 1080 的圖片,加載到內(nèi)存后占用的內(nèi)存大小為1920 * 1080 * 4 = 7.91M
可以通過設(shè)置 inPreferredConfig 參數(shù)來設(shè)置對應(yīng)的色彩模式,例如,一個不包含透明通道的圖片,我們可以將其設(shè)置為RGB_565,即保證了圖片的質(zhì)量,又減少了內(nèi)存的占用。
此時,一張 1920 * 1080 的圖片加載到內(nèi)存后的內(nèi)存大小為 1920 * 1080 * 2 = 3.955M,比默認(rèn)情況下的內(nèi)存占用減小了一半。
通過緩存策略也可以一定程度上的優(yōu)化內(nèi)存占用問題,比如 Glide 框架中采用了三級本地緩存策略來實現(xiàn)Bitmap的優(yōu)化,通過設(shè)置活動緩存、LRU內(nèi)存緩存和本地緩存。對于相同參數(shù)的ImageView,在內(nèi)存中只保存一份,以此來減少內(nèi)存大小。
例如我們只在 hdpi 的目錄下放置了一張 100 * 100 的圖片,那么根據(jù)換算關(guān)系,分辨率匹配到 xxhdpi 的手機去引用這張圖片時就會被拉伸到 200*200。需要注意到在這種情況下,內(nèi)存占用是會顯著提高的。對于不希望被拉伸的圖片,需要放到 assets 或者 nodpi 的目錄下。
可以使用更加輕量級的數(shù)據(jù)結(jié)構(gòu)。例如,我們可以考慮使用 ArrayMap/SparseArray 而不是 HashMap 等傳統(tǒng)數(shù)據(jù)結(jié)構(gòu),相比起 Android 系統(tǒng)專門為移動操作系統(tǒng)編寫的 ArrayMap 容器,在大多數(shù)情況下,HashMap 都顯示效率低下,更占內(nèi)存。另外,SparseArray更加高效在于,避免了對key與value的自動裝箱,并且避免了裝箱后的解箱。
內(nèi)存抖動是指在短時間內(nèi)突然創(chuàng)建大量的對象,頻繁的引發(fā)GC回收,造成內(nèi)存波動的情況。在開發(fā)中應(yīng)該避免頻繁的創(chuàng)建對象,來避免內(nèi)存抖動。因為內(nèi)存抖動會頻繁觸發(fā) GC,而GC又會引起 STW 問題,直接影響程序的性能。
比如在繪制自定義View的時候一定要避免在onDraw或者onMeasure中創(chuàng)建對象。
Android系統(tǒng)提供了一些回調(diào)來通知當(dāng)前應(yīng)用的內(nèi)存使用情況,比如下邊的兩個方法:
onLowMemory() 通常來說,當(dāng)所有的Background應(yīng)用都被kill掉的時候,forground應(yīng)用會收到onLowMemory()的回調(diào)。在這種情況下,需要盡快釋放當(dāng)前應(yīng)用的非必須的內(nèi)存資源,從而確保系統(tǒng)能夠繼續(xù)穩(wěn)定運行。尤其是要釋放Glide中緩存的Bitmap資源,通過調(diào)用Glide.onLowMemory方法進行資源回收。
onTrimMemory() Android系統(tǒng)從4.0開始還提供了onTrimMemory()的回調(diào),當(dāng)系統(tǒng)內(nèi)存達到某些條件的時候,所有正在運行的應(yīng)用都會收到這個回調(diào),同時在這個回調(diào)里面會傳遞以下的參數(shù),代表不同的內(nèi)存使用情況,收到onTrimMemory()回調(diào)的時候,需要根據(jù)傳遞的參數(shù)類型進行判斷,合理的選擇釋放自身的一些內(nèi)存占用,一方面可以提高系統(tǒng)的整體運行流暢度,另外也可以避免自己被系統(tǒng)判斷為優(yōu)先需要殺掉的應(yīng)用。例如調(diào)用Glide.onTrimMemory()來進行bitmap的回收。
在debug模式下會一直開著LeakCanary來檢測內(nèi)存泄漏問題,根據(jù)LeanCannary提供的引用連可以快速定位到內(nèi)存泄漏的位置。
在一個功能開發(fā)完成后可以通過Profiler來檢測APP的內(nèi)存使用情況。反復(fù)的打開關(guān)閉頁面,然后觸發(fā)GC,內(nèi)存是否能夠減少。
MAT提供了很強大的功能,可以查看對象的深堆、淺堆的內(nèi)存大小等。
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“Android內(nèi)存優(yōu)化策略的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。