




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第Android內(nèi)存優(yōu)化操作方法梳理總結(jié)目錄內(nèi)存泄露非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實(shí)例注冊(cè)對(duì)象未注銷或資源對(duì)象未關(guān)閉類的靜態(tài)變量引用耗費(fèi)資源過(guò)多的實(shí)例Handler引發(fā)的內(nèi)存泄露集合引發(fā)的內(nèi)存泄露檢測(cè)工具LeakCanaryAndroidStudioProfiler內(nèi)存溢出Bitmap優(yōu)化內(nèi)存抖動(dòng)
內(nèi)存泄露
內(nèi)存泄漏就是在當(dāng)前應(yīng)用周期內(nèi)不再使用的對(duì)象被GCRoots引用,導(dǎo)致不能回收,使實(shí)際可使用內(nèi)存變小,通俗點(diǎn)講,就是無(wú)法回收無(wú)用對(duì)象。這里總結(jié)了實(shí)際開發(fā)中常見的一些內(nèi)存泄露的場(chǎng)景示例和解決方案。
非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實(shí)例
該實(shí)例的生命周期和應(yīng)用一樣長(zhǎng),非靜態(tài)內(nèi)部類會(huì)自動(dòng)持有外部類的引用,這就導(dǎo)致該靜態(tài)實(shí)例一直持有外部類Activity的引用。
classMemoryActivity:AppCompatActivity(){
companionobject{
vartest:Test=null
overridefunonCreate(savedInstanceState:Bundle){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_memory)
test=Test()
innerclassTest{
}
解決方案:將非靜態(tài)內(nèi)部類改為靜態(tài)內(nèi)部類
classMemoryActivity:AppCompatActivity(){
companionobject{
vartest:Test=null
overridefunonCreate(savedInstanceState:Bundle){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_memory)
test=Test()
//kotlin的靜態(tài)內(nèi)部類
classTest{
}
注冊(cè)對(duì)象未注銷或資源對(duì)象未關(guān)閉
注冊(cè)了像BraodcastReceiver,EventBus這種,沒(méi)有在頁(yè)面銷毀時(shí)注銷的話,會(huì)引發(fā)泄露問(wèn)題,所以應(yīng)該在Activity銷毀時(shí)及時(shí)注銷。
類的靜態(tài)變量引用耗費(fèi)資源過(guò)多的實(shí)例
類的靜態(tài)變量生命周期等于應(yīng)用程序的生命周期,若其引用耗資過(guò)多的實(shí)例,如Context,當(dāng)引用實(shí)例需結(jié)束生命周期時(shí),會(huì)因靜態(tài)變量的持有而無(wú)法被回收,從而出現(xiàn)內(nèi)存泄露,這種情況比較常見的有單例持有context。
classSingleTonprivateconstructor(valcontext:Context){
companionobject{
privatevarinstance:SingleTon=null
fungetInstance(context:Context)=
if(instance==null)SingleTon(context)elseinstance!!
}
當(dāng)我們?cè)贏ctivity中使用時(shí),當(dāng)Activity銷毀,就會(huì)出現(xiàn)內(nèi)存泄露
classMemoryActivity:AppCompatActivity(){
overridefunonCreate(savedInstanceState:Bundle){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_memory)
SingleTon.getInstance(this)
}
這種情況可以使用applicationContext,因?yàn)锳pplication的生命周期就等于整個(gè)應(yīng)用的生命周期
classSingleTonprivateconstructor(context:Context){
privatevarcontext:Context
init{
this.context=context.applicationContext
companionobject{
privatevarinstance:SingleTon=null
fungetInstance(context:Context)=
if(instance==null)SingleTon(context)elseinstance!!
}
Handler引發(fā)的內(nèi)存泄露
classMemoryActivity:AppCompatActivity(){
privatevaltag=javaClass.simpleName
privatevalhandler=object:Handler(Looper.getMainLooper()){
overridefunhandleMessage(msg:Message){
Log.i(tag,"handleMessage:$msg")
overridefunonCreate(savedInstanceState:Bundle){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_memory)
thread(start=true){
handler.sendEmptyMessageDelayed(1,10000)
}
當(dāng)Activity被finish時(shí),延遲發(fā)送的消息仍會(huì)存活在UI線程的消息隊(duì)列中,直到10s后才被處理,這個(gè)消息持有handler的引用,由于非靜態(tài)內(nèi)部類或匿名類會(huì)隱式持有外部類的引用,handler隱式持有外部類也就是Activity的引用,這個(gè)引用會(huì)一直存在直到這個(gè)消息被處理,所以垃圾回收機(jī)制就沒(méi)法回收而導(dǎo)致內(nèi)存泄露。
解決方案:靜態(tài)內(nèi)部類+弱引用,靜態(tài)內(nèi)部類不會(huì)持有外部類的引用,如需handler內(nèi)調(diào)用外部類Activity的方法的話,可以讓handler持有外部類Activity的弱引用,這樣Activity就不會(huì)有泄露風(fēng)險(xiǎn)了。
classMemoryActivity:AppCompatActivity(){
companionobject{
privateconstvaltag="uncle"
privatelateinitvarhandler:Handler
overridefunonCreate(savedInstanceState:Bundle){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_memory)
handler=MyHandler(this)
thread(start=true){
handler.sendEmptyMessageDelayed(1,10000)
classMyHandler(activity:Activity):Handler(Looper.getMainLooper()){
privatevalreference=WeakReference(activity)
overridefunhandleMessage(msg:Message){
super.handleMessage(msg)
if(reference.get()!=null){
Log.i(tag,"handleMessage:$msg")
}
集合引發(fā)的內(nèi)存泄露
先看個(gè)例子,我們定義一個(gè)棧,裝著所有的Activity
classGlobalData{
companionobject{
valactivityStack=StackActivity()
然后每啟動(dòng)一個(gè)Activity,就把此Activity加進(jìn)去,這個(gè)時(shí)候,如果你沒(méi)有在Activity銷毀時(shí)清掉集合中對(duì)應(yīng)的引用,就會(huì)出現(xiàn)泄露問(wèn)題。當(dāng)然,實(shí)際開發(fā)中我們不會(huì)寫這么差的代碼,這只是簡(jiǎn)單提個(gè)醒,需要注意一下集合中的一些引用,如果會(huì)導(dǎo)致泄露的,記得及時(shí)在銷毀時(shí)清掉。
classMemoryActivity:AppCompatActivity(){
overridefunonCreate(savedInstanceState:Bundle){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_memory)
GlobalData.activityStack.push(this)
}
檢測(cè)工具
排查內(nèi)存泄露,需要一些工具的支持,這里主要介紹常用的兩個(gè),LeakCanary和AndroidStudioProfiler。
LeakCanary
一行代碼引入
debugImplementationcom.squareup.leakcanary:leakcanary-android:2.9.1
當(dāng)你測(cè)試包安裝時(shí),手機(jī)上就會(huì)有個(gè)伴生APP,用來(lái)記錄內(nèi)存泄露信息的。
就拿上面集合引發(fā)的泄露例子來(lái)說(shuō),LeakCanary就會(huì)彈出通知并且LeaksAPP中顯示內(nèi)存泄露信息,我們以此來(lái)定位內(nèi)存泄露問(wèn)題。
AndroidStudioProfiler
同樣,我們拿上面集合的泄漏例子來(lái)看,首先,我們點(diǎn)擊MEMORY
然后,普通的內(nèi)存問(wèn)題選擇Captureheapdump就行了
點(diǎn)擊Record,就會(huì)抓取一段時(shí)間的內(nèi)存分配信息
Leaks就是記錄內(nèi)存泄漏的,然后我們點(diǎn)擊進(jìn)去,就可以看到具體類位置了
再點(diǎn)擊進(jìn)去具體的類,就可以看到泄漏的原因啦
內(nèi)存溢出
Android系統(tǒng)中每個(gè)應(yīng)用程序可以向系統(tǒng)申請(qǐng)一定的內(nèi)存,當(dāng)申請(qǐng)的內(nèi)存不夠用的時(shí)候,就會(huì)產(chǎn)生內(nèi)存溢出,俗稱OOM,全稱OutOfMemory,就是內(nèi)存用完了。在實(shí)際開發(fā)中,出現(xiàn)這種現(xiàn)象通常是因?yàn)閮?nèi)存泄露太多或大圖加載問(wèn)題,內(nèi)存泄露上面已經(jīng)講了,那么,下面就主要講講圖片的優(yōu)化吧!
Bitmap優(yōu)化
(1)及時(shí)回收Bitmap內(nèi)存,這時(shí)可能有人就要問(wèn)了,Android有自己的垃圾回收機(jī)制,為什么還要我們?nèi)セ厥漳??因?yàn)樯葿itmap最終是通過(guò)JNI方法實(shí)現(xiàn)的,也就是說(shuō),Bitmap的加載包含兩部分的內(nèi)存區(qū)域,一是Java部分,一是C部分。Java部分會(huì)自動(dòng)回收,但是C部分不會(huì),所以需要調(diào)用recycle來(lái)釋放C部分的內(nèi)存。那如果不調(diào)用就一定會(huì)出現(xiàn)泄露嗎?那也不是的,Android每個(gè)應(yīng)用都在獨(dú)立的進(jìn)程,進(jìn)程被關(guān)掉的話,內(nèi)存也就都被釋放了。
if(bitmap!=null!bitmap.isRecycled){
bitmap.recycle()
bitmap=null
}
(2)捕獲異常,Bitmap在使用的時(shí)候,最好捕獲一下OutOfMemoryError以免crash掉,你還可以設(shè)置一個(gè)默認(rèn)的圖片。
varbitmap:Bitmap=null
try{
bitmap=BitmapFactory.decodeFile(filePath)
imageView.setImageBitmap(bitmap)
}catch(e:OutOfMemoryError){
//捕獲異常
if(bitmap==null){
imageView.setImageDrawable(ContextCompat.getDrawable(this,R.drawable.picture))
}
(3)壓縮,對(duì)于分辨率比較高的圖片,我們應(yīng)該加載一個(gè)縮小版,這里采用的是采樣率壓縮法。
valoptions=BitmapFactory.Options()
//設(shè)置為true可以讓解析方法禁止為bitmap分配內(nèi)存,返回null,同時(shí)能獲取到長(zhǎng)寬值,從而根據(jù)情況進(jìn)行壓縮
options.inJustDecodeBounds=true
BitmapFactory.decodeResource(resources,R.drawable.large_picture,options)
valimgHeight=options.outHeight
valimgWidth=options.outWidth
//通過(guò)改變inSampleSize的值來(lái)壓縮圖片
varinSampleSize=1
//imgWidth為圖片的寬,viewWidth為實(shí)際控件的寬
if(imgHeightviewHeight||imgWidthviewWidth){
valheightRatio=round(imgHeight/viewHeight.toFloat()).toInt()
valwidthRatio=round(imgWidth/viewWidth.toFloat()).toInt()
//選擇最小比率作為inSampleSize的值,可保證最終圖片的寬高一定大于等于目標(biāo)的寬高
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度護(hù)膚品牌全國(guó)獨(dú)家代理權(quán)合作協(xié)議
- 2025年智能養(yǎng)殖基地冷鏈物流體系升級(jí)改造貸款合同
- 2025年智慧社區(qū)安防系統(tǒng)建設(shè)合作協(xié)議
- 2025年北京居民戶口遷移與全面養(yǎng)老服務(wù)體系合同
- 2025年國(guó)企助理考試題庫(kù)
- 2025年高端手機(jī)租賃與銷售代理合作協(xié)議范本
- 2025自考審計(jì)試題及答案
- 2025年成人自閉癥測(cè)試題及答案
- 2025年文化中心演出場(chǎng)地租賃及配套服務(wù)全方位合作協(xié)議
- 2025中文教師資格證考試題庫(kù)及答案
- 特種設(shè)備安全管理-使用知識(shí)
- 難治性高血壓的治療策略
- 肝臟腫瘤的影像診斷及鑒別診斷講座演示文稿
- H35-462(5G中級(jí))認(rèn)證考試題庫(kù)(附答案)
- 2023年全科醫(yī)師轉(zhuǎn)崗培訓(xùn)理論考試試題及答案
- GB/T 17642-1998土工合成材料非織造復(fù)合土工膜
- 3C認(rèn)證全套體系文件(手冊(cè)+程序文件)
- 魚類繁殖與發(fā)育課件
- (完整)五金材料采購(gòu)清單
- 政企業(yè)務(wù)認(rèn)知題庫(kù)V1
- 制造執(zhí)行系統(tǒng)的功能與實(shí)踐最新ppt課件(完整版)
評(píng)論
0/150
提交評(píng)論