




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第Android內(nèi)存優(yōu)化操作方法梳理總結(jié)目錄內(nèi)存泄露非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實例注冊對象未注銷或資源對象未關(guān)閉類的靜態(tài)變量引用耗費資源過多的實例Handler引發(fā)的內(nèi)存泄露集合引發(fā)的內(nèi)存泄露檢測工具LeakCanaryAndroidStudioProfiler內(nèi)存溢出Bitmap優(yōu)化內(nèi)存抖動
內(nèi)存泄露
內(nèi)存泄漏就是在當(dāng)前應(yīng)用周期內(nèi)不再使用的對象被GCRoots引用,導(dǎo)致不能回收,使實際可使用內(nèi)存變小,通俗點講,就是無法回收無用對象。這里總結(jié)了實際開發(fā)中常見的一些內(nèi)存泄露的場景示例和解決方案。
非靜態(tài)內(nèi)部類創(chuàng)建靜態(tài)實例
該實例的生命周期和應(yīng)用一樣長,非靜態(tài)內(nèi)部類會自動持有外部類的引用,這就導(dǎo)致該靜態(tài)實例一直持有外部類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{
}
注冊對象未注銷或資源對象未關(guān)閉
注冊了像BraodcastReceiver,EventBus這種,沒有在頁面銷毀時注銷的話,會引發(fā)泄露問題,所以應(yīng)該在Activity銷毀時及時注銷。
類的靜態(tài)變量引用耗費資源過多的實例
類的靜態(tài)變量生命周期等于應(yīng)用程序的生命周期,若其引用耗資過多的實例,如Context,當(dāng)引用實例需結(jié)束生命周期時,會因靜態(tài)變量的持有而無法被回收,從而出現(xiàn)內(nèi)存泄露,這種情況比較常見的有單例持有context。
classSingleTonprivateconstructor(valcontext:Context){
companionobject{
privatevarinstance:SingleTon=null
fungetInstance(context:Context)=
if(instance==null)SingleTon(context)elseinstance!!
}
當(dāng)我們在Activity中使用時,當(dāng)Activity銷毀,就會出現(xiàn)內(nèi)存泄露
classMemoryActivity:AppCompatActivity(){
overridefunonCreate(savedInstanceState:Bundle){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_memory)
SingleTon.getInstance(this)
}
這種情況可以使用applicationContext,因為Application的生命周期就等于整個應(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時,延遲發(fā)送的消息仍會存活在UI線程的消息隊列中,直到10s后才被處理,這個消息持有handler的引用,由于非靜態(tài)內(nèi)部類或匿名類會隱式持有外部類的引用,handler隱式持有外部類也就是Activity的引用,這個引用會一直存在直到這個消息被處理,所以垃圾回收機制就沒法回收而導(dǎo)致內(nèi)存泄露。
解決方案:靜態(tài)內(nèi)部類+弱引用,靜態(tài)內(nèi)部類不會持有外部類的引用,如需handler內(nèi)調(diào)用外部類Activity的方法的話,可以讓handler持有外部類Activity的弱引用,這樣Activity就不會有泄露風(fēng)險了。
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)存泄露
先看個例子,我們定義一個棧,裝著所有的Activity
classGlobalData{
companionobject{
valactivityStack=StackActivity()
然后每啟動一個Activity,就把此Activity加進去,這個時候,如果你沒有在Activity銷毀時清掉集合中對應(yīng)的引用,就會出現(xiàn)泄露問題。當(dāng)然,實際開發(fā)中我們不會寫這么差的代碼,這只是簡單提個醒,需要注意一下集合中的一些引用,如果會導(dǎo)致泄露的,記得及時在銷毀時清掉。
classMemoryActivity:AppCompatActivity(){
overridefunonCreate(savedInstanceState:Bundle){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_memory)
GlobalData.activityStack.push(this)
}
檢測工具
排查內(nèi)存泄露,需要一些工具的支持,這里主要介紹常用的兩個,LeakCanary和AndroidStudioProfiler。
LeakCanary
一行代碼引入
debugImplementationcom.squareup.leakcanary:leakcanary-android:2.9.1
當(dāng)你測試包安裝時,手機上就會有個伴生APP,用來記錄內(nèi)存泄露信息的。
就拿上面集合引發(fā)的泄露例子來說,LeakCanary就會彈出通知并且LeaksAPP中顯示內(nèi)存泄露信息,我們以此來定位內(nèi)存泄露問題。
AndroidStudioProfiler
同樣,我們拿上面集合的泄漏例子來看,首先,我們點擊MEMORY
然后,普通的內(nèi)存問題選擇Captureheapdump就行了
點擊Record,就會抓取一段時間的內(nèi)存分配信息
Leaks就是記錄內(nèi)存泄漏的,然后我們點擊進去,就可以看到具體類位置了
再點擊進去具體的類,就可以看到泄漏的原因啦
內(nèi)存溢出
Android系統(tǒng)中每個應(yīng)用程序可以向系統(tǒng)申請一定的內(nèi)存,當(dāng)申請的內(nèi)存不夠用的時候,就會產(chǎn)生內(nèi)存溢出,俗稱OOM,全稱OutOfMemory,就是內(nèi)存用完了。在實際開發(fā)中,出現(xiàn)這種現(xiàn)象通常是因為內(nèi)存泄露太多或大圖加載問題,內(nèi)存泄露上面已經(jīng)講了,那么,下面就主要講講圖片的優(yōu)化吧!
Bitmap優(yōu)化
(1)及時回收Bitmap內(nèi)存,這時可能有人就要問了,Android有自己的垃圾回收機制,為什么還要我們?nèi)セ厥漳??因為生成Bitmap最終是通過JNI方法實現(xiàn)的,也就是說,Bitmap的加載包含兩部分的內(nèi)存區(qū)域,一是Java部分,一是C部分。Java部分會自動回收,但是C部分不會,所以需要調(diào)用recycle來釋放C部分的內(nèi)存。那如果不調(diào)用就一定會出現(xiàn)泄露嗎?那也不是的,Android每個應(yīng)用都在獨立的進程,進程被關(guān)掉的話,內(nèi)存也就都被釋放了。
if(bitmap!=null!bitmap.isRecycled){
bitmap.recycle()
bitmap=null
}
(2)捕獲異常,Bitmap在使用的時候,最好捕獲一下OutOfMemoryError以免crash掉,你還可以設(shè)置一個默認的圖片。
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)壓縮,對于分辨率比較高的圖片,我們應(yīng)該加載一個縮小版,這里采用的是采樣率壓縮法。
valoptions=BitmapFactory.Options()
//設(shè)置為true可以讓解析方法禁止為bitmap分配內(nèi)存,返回null,同時能獲取到長寬值,從而根據(jù)情況進行壓縮
options.inJustDecodeBounds=true
BitmapFactory.decodeResource(resources,R.drawable.large_picture,options)
valimgHeight=options.outHeight
valimgWidth=options.outWidth
//通過改變inSampleSize的值來壓縮圖片
varinSampleSize=1
//imgWidth為圖片的寬,viewWidth為實際控件的寬
if(imgHeightviewHeight||imgWidthviewWidth){
valheightRatio=round(imgHeight/viewHeight.toFloat()).toInt()
valwidthRatio=round(imgWidth/viewWidth.toFloat()).toInt()
//選擇最小比率作為inSampleSize的值,可保證最終圖片的寬高一定大于等于目標的寬高
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 敬老院五保戶合同協(xié)議書
- 木工承包合同協(xié)議書
- 物流公司勞務(wù)合同協(xié)議書
- 離職協(xié)議合同協(xié)議書
- 松樹的承包合同協(xié)議書
- 藝術(shù)培訓(xùn)服務(wù)合同協(xié)議書
- 貸款合同協(xié)議書
- 爆破合同協(xié)議書范本
- 場地項目經(jīng)理合同協(xié)議書
- 地板打蠟合同協(xié)議書范本
- 微博運營方案及工作計劃
- 《體育精神》-體育故事與體育精神培養(yǎng)教案
- 部編本一年級下冊1、吃水不忘挖井人名師公開課獲獎?wù)n件百校聯(lián)賽一等獎?wù)n件
- 投資合同:有限公司投資協(xié)議
- 四川大學(xué)華西口腔醫(yī)院臨床研究醫(yī)學(xué)倫理審查申請表【模板】
- 拖欠房租通知書范文
- 年產(chǎn)萬噸的氯乙烯合成工段的工藝設(shè)計
- 2024年湖北省中考歷史試卷附答案
- 2024年銀行校園招聘入職考試模擬試題及答案(共三套)
- 2024年新疆烏魯木齊市中考化學(xué)適應(yīng)性試卷
- 民法典之合同篇課件
評論
0/150
提交評論