Android Note - 内存优化
內(nèi)存優(yōu)化是Android性能優(yōu)化的重點(diǎn)內(nèi)容,一般來說,談及性能優(yōu)化,肯定避不開內(nèi)存優(yōu)化。雖然現(xiàn)在手機(jī)內(nèi)存都很大,但并不意味著我們的App在使用內(nèi)存時(shí)能“為所欲為”。這篇就簡單地總結(jié)一下關(guān)于內(nèi)存優(yōu)化要注意的一些事項(xiàng)。
進(jìn)程級別的內(nèi)存策略
我們知道,Android 系統(tǒng)是一個(gè)基于 Linux 的開源系統(tǒng),使用的是 Dalvik / Android Runtime 作為對應(yīng)的虛擬機(jī)來執(zhí)行代碼。底層內(nèi)存分配機(jī)制在這里就不詳述了,只看 Application Framework 這一層。
首先,Android 中的內(nèi)存分配由 ActivityManagerService 統(tǒng)一管理。這是一個(gè)很重要的類,除了內(nèi)存管理之外,它還管理了 Activity 生命周期,啟動(dòng)行為,消息派發(fā)等功能。當(dāng)用戶點(diǎn)擊應(yīng)用的啟動(dòng)圖標(biāo)時(shí), ActivityManagerService 會(huì)請求系統(tǒng)創(chuàng)建一個(gè)進(jìn)程,當(dāng)進(jìn)程創(chuàng)建完成之后,綁定給 ActivityManagerService,這時(shí)才會(huì)開始 App 本身的生命周期。
而關(guān)于內(nèi)存回收這塊,Application Framework 給創(chuàng)建的進(jìn)程規(guī)定了五個(gè)的回收類型優(yōu)先級,即從最先被回收到最后被回收,分別是:
- Empty process 空進(jìn)程
- Background process 后臺(tái)進(jìn)程
- Service process 服務(wù)進(jìn)程
- Visible process 可見進(jìn)程
- Foreground process 前臺(tái)進(jìn)程
然后在 ActivityManagerService 中,會(huì)對所有進(jìn)程進(jìn)行評分,并將評分同步到 Linux 內(nèi)核中,最終由內(nèi)核來執(zhí)行內(nèi)存回收
對象級別的內(nèi)存策略
關(guān)于對象級別的內(nèi)存管理策略,由于是應(yīng)用程序自動(dòng)管理內(nèi)存分配以及內(nèi)存回收(Java GC),能操作的有限,但是基本的概念還是要了解的,因?yàn)楫?dāng)你知道對象/變量在內(nèi)存中是如何分配,以及分配到堆/棧/方法區(qū)的時(shí)候,在寫代碼的時(shí)候就會(huì)有意規(guī)避一些問題,達(dá)到內(nèi)存優(yōu)化的效果。
Android常見內(nèi)存問題
內(nèi)存泄漏
內(nèi)存泄漏 Memory Leak,指的是內(nèi)存申請并使用完畢以后,系統(tǒng)因?yàn)槟承┰驘o法回收該內(nèi)存塊的情況。其實(shí)質(zhì)也是長生命周期對象持有短生命周期的對象,導(dǎo)致短生命周期對象需要被回收時(shí),由于長生命周期的對象持有無法被回收的現(xiàn)象。
在Android中,以下幾個(gè)場景容易出現(xiàn)內(nèi)存泄漏。
單例對象使用了非全局的 Context
這個(gè)是初學(xué)者容易犯的錯(cuò)誤,在構(gòu)造一個(gè)單例對象時(shí),往往需要使用 Context 對象來初始化構(gòu)造函數(shù),并持有一個(gè) Context對象,這時(shí)如果傳入一個(gè)非全局的 Context ,會(huì)導(dǎo)致該 Context對象在 GC 時(shí)無法回收,造成內(nèi)存泄漏。
解決方案:單例使用 ApplicationContext ,這個(gè)對象的生命周期是整個(gè)應(yīng)用的生命周期,不會(huì)導(dǎo)致泄漏
匿名內(nèi)部類 / 非靜態(tài)內(nèi)部類 / 異步線程 / Handler 持有外部類的引用
這也是常見的內(nèi)存泄漏易于出現(xiàn)的場景。舉例來說,我們現(xiàn)在經(jīng)常使用 Rxjava + Retrofit + OkHttp 來構(gòu)建網(wǎng)絡(luò)請求。有時(shí)候會(huì)碰到網(wǎng)速過慢導(dǎo)致網(wǎng)絡(luò)請求返回慢或者超時(shí)的情況。這時(shí)如果我們關(guān)閉了當(dāng)前頁面,網(wǎng)絡(luò)請求結(jié)果仍然會(huì)被觀察者接受并刷新UI。這時(shí)本來要被回收的UI對象由于被觀察者持有,無法回收,就導(dǎo)致了內(nèi)存泄漏。
解決方案:
資源未關(guān)閉導(dǎo)致無法回收
這也是經(jīng)常被提到的點(diǎn),注冊并使用后,忘記在生命周期結(jié)束時(shí)解綁,導(dǎo)致無法回收。
解決方案:BroadcastReceiver、ContentObserver、File、Bitmap、Timer、EventBus 等都是需要解綁或者清空的,要養(yǎng)成直覺
WebView不要在布局中定義
這個(gè)是網(wǎng)絡(luò)上一篇文章里看到的,我想現(xiàn)在應(yīng)該沒有多少人會(huì)在布局里定義 WebView 吧(還有 Fragment )
解決方案:在代碼中構(gòu)造WebView對象,創(chuàng)建時(shí)上下文使用 ApplicationContext
內(nèi)存溢出
內(nèi)存溢出 Out Of Memory ,是指應(yīng)用的內(nèi)存申請超出了當(dāng)前所能申請的最大內(nèi)存容量,導(dǎo)致應(yīng)用出現(xiàn)一系列問題甚至被系統(tǒng)殺掉進(jìn)程。在 Android 中出現(xiàn)內(nèi)存溢出,主要是因?yàn)橐韵略蛞稹?/p>
使用 Bitmap 并且未優(yōu)化
Bitmap 是產(chǎn)生內(nèi)存溢出的大戶,如果沒有經(jīng)過任何優(yōu)化,直接加載一個(gè) Bitmap 的話,會(huì)導(dǎo)致該對象吃掉大量內(nèi)存。
解決方案:
短時(shí)間創(chuàng)建大量對象
這個(gè)常見于列表組件的加載。加載列表時(shí)如果不優(yōu)化,同一時(shí)間內(nèi)創(chuàng)建了過多對象,就會(huì)造成內(nèi)存溢出。
解決方案:
其他內(nèi)存溢出的場景和解決方案
轉(zhuǎn)載于:https://juejin.im/post/5cc965ffe51d453acd5050a4
總結(jié)
以上是生活随笔為你收集整理的Android Note - 内存优化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ERP与进销存软件的区别
- 下一篇: 基于Android 虹软人脸、人证对比