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