// 保證非靜态内部類的執行個體隻有1個
if (innerClass == null)
innerClass = new InnerClass();
}
// 非靜态内部類的定義
private class InnerClass {
//…
}
}
// 造成記憶體洩露的原因:
// a. 當TestActivity銷毀時,因非靜态内部類單例的引用(innerClass)的生命周期 = 應用App的生命周期、持有外部類TestActivity的引用
// b. 故 TestActivity無法被GC回收,進而導緻記憶體洩漏
- 解決方案
- 将非靜态内部類設定為:靜态内部類(靜态内部類預設不持有外部類的引用)
- 該内部類抽取出來封裝成一個單例
- 盡量 避免 非靜态内部類所建立的執行個體 = 靜态
若需使用Context,建議使用 Application 的 Context
5.3.2 多線程:AsyncTask、實作Runnable接口、繼承Thread類
- 儲備知識多線程的使用方法 = 非靜态内部類 / 匿名類;即 線程類 屬于 非靜态内部類 / 匿名類
- 洩露原因當 工作線程正在處理任務 & 外部類需銷毀時, 由于 工作線程執行個體 持有外部類引用,将使得外部類無法被垃圾回收器(GC)回收,進而造成 記憶體洩露
多線程主要使用的是:AsyncTask、實作Runnable接口 & 繼承Thread類前3者記憶體洩露的原理相同,此處主要以繼承Thread類 為例說明
執行個體示範
public class MainActivity extends AppCompatActivity {
public static final String TAG = “carson:”;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 通過建立的内部類 實作多線程
new MyThread().start();
}
// 自定義的Thread子類
private class MyThread extends Thread{
@Override
public void run() {
try {
Thread.sleep(5000);
Log.d(TAG, “執行了多線程”);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class MainActivity extends AppCompatActivity {
public static final String TAG = “carson:”;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 通過匿名内部類 實作多線程
new Thread() {
@Override
public void run() {
try {
Thread.sleep(5000);
Log.d(TAG, “執行了多線程”);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
}
// 工作線程Thread類屬于非靜态内部類 / 匿名内部類,運作時預設持有外部類的引用
// 當工作線程運作時,若外部類MainActivity需銷毀
// 由于此時工作線程類執行個體持有外部類的引用,将使得外部類無法被垃圾回收器(GC)回收,進而造成 記憶體洩露
- 解決方案從上面可看出,造成記憶體洩露的原因有2個關鍵條件:
- 存在 ”工作線程執行個體 持有外部類引用“ 的引用關系
- 工作線程執行個體的生命周期 > 外部類的生命周期,即工作線程仍在運作 而 外部類需銷毀解決方案的思路 = 使得上述任1條件不成立 即可。
// 共有2個解決方案:靜态内部類 & 當外部類結束生命周期時,強制結束線程
// 具體描述如下
public class MainActivity extends AppCompatActivity {
public static final String TAG = “carson:”;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 通過建立的内部類 實作多線程
new MyThread().start();
}
// 分析1:自定義Thread子類
// 設定為:靜态内部類
private static class MyThread extends Thread{
@Override
public void run() {
try {
Thread.sleep(5000);
Log.d(TAG, “執行了多線程”);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
Thread.stop();
// 外部類Activity生命周期結束時,強制結束線程
}
5.3.3 消息傳遞機制:HandlerAndroid 記憶體洩露:詳解 Handler 記憶體洩露的原因與解決方案https://www.jianshu.com/p/031515d8a7ca
5.4 資源對象使用後未關閉
- 洩露原因對于資源的使用(如 廣播BraodcastReceiver、檔案流File、資料庫遊标Cursor、圖檔資源Bitmap等),若在Activity銷毀時無及時關閉 / 登出這些資源,則這些資源将不會被回收,進而造成記憶體洩漏
- 解決方案在Activity銷毀時 及時關閉 / 登出資源
// 對于 廣播BraodcastReceiver:登出注冊
unregisterReceiver()
// 對于 檔案流File:關閉流
InputStream / OutputStream.close()
// 對于資料庫遊标cursor:使用後關閉遊标
cursor.close()
// 對于 圖檔資源Bitmap:Android配置設定給圖檔的記憶體隻有8M,若1個Bitmap對象占記憶體較多,當它不再被使用時,應調用recycle()回收此對象的像素所占用的記憶體;最後再賦為null
Bitmap.recycle();
Bitmap = null;
// 對于動畫(屬性動畫)
// 将動畫設定成無限循環播放repeatCount = “infinite”後
// 在Activity退出時記得停止動畫
5.5 其他使用
- 除了上述4種常見情況,還有一些日常的使用會導緻記憶體洩露
- 主要包括:Context、WebView、Adapter,具體介紹如下
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5iY5MzMjV2N5YjN1QmZwcTMkVDN3YjZ2gDM2gjMmlDMk9CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
5.6 總結下面,我将用一張圖總結Android中記憶體洩露的原因 & 解決方案
6. 輔助分析記憶體洩露的工具
- 哪怕完全了解 記憶體洩露的原因,但難免還是會出現記憶體洩露的現象
- 下面将簡單介紹幾個主流的分析記憶體洩露的工具,分别是
- MAT(Memory Analysis Tools)
- Heap Viewer
- Allocation Tracker
- Android Studio 的 Memory Monitor
- LeakCanary
6.1 MAT(Memory Analysis Tools)
- 定義:一個Eclipse的 Java Heap 記憶體分析工具 ->>下載下傳位址
- 作用:檢視目前記憶體占用情況
通過分析 Java 程序的記憶體快照 HPROF 分析,快速計算出在記憶體中對象占用的大小,檢視哪些對象不能被垃圾收集器回收 & 可通過視圖直覺地檢視可能造成這種結果的對象
具體使用:MAT使用攻略
6.2 Heap Viewer
定義:一個的 Java Heap 記憶體分析工具作用:檢視目前記憶體快照
可檢視 分别有哪些類型的資料在堆記憶體總 & 各種類型資料的占比情況
具體使用:Heap Viewer使用攻略
6.3 Allocation Tracker
簡介:一個記憶體追蹤分析工具作用:追蹤記憶體配置設定資訊,按順序排列具體使用:Allocation Tracker使用攻略
6.4 Memory Monitor
簡介:一個 Android Studio 自帶 的圖形化檢測記憶體工具作用:跟蹤系統 / 應用的記憶體使用情況。核心功能如下
具體使用:Android Studio 的 Memory Monitor使用攻略
6.5 LeakCanary
簡介:一個square出品的Android開源庫 ->>下載下傳位址作用:檢測記憶體洩露具體使用:https://www.liaohuqiu.net/cn/posts/leak-canary/
7. 總結
本文 全面介紹了記憶體洩露的本質、原因 & 解決方案,希望大家在開發時盡量避免出現記憶體洩露
文章不易,如果大家喜歡這篇文章,或者對你有幫助希望大家多多點贊轉發關注哦。文章會持續更新的。絕對幹貨!!!
總結
最後為了幫助大家深刻了解Android相關知識點的原理以及面試相關知識,這裡放上相關的我搜集整理的14套騰訊、位元組跳動、阿裡、百度等2020面試真題解析,我把技術點整理成了視訊和PDF(實際上比預期多花了不少精力),包知識脈絡 + 諸多細節。
網上學習 Android的資料一大堆,但如果學到的知識不成體系,遇到問題時隻是淺嘗辄止,不再深入研究,那麼很難做到真正的技術提升。希望這份系統化的技術體系對大家有一個方向參考。
術體系](https://github.com/a120464/Android-P7/blob/master/Android%E5%BC%80%E5%8F%91%E4%B8%8D%E4%BC%9A%E8%BF%99%E4%BA%9B%EF%BC%9F%E5%A6%82%E4%BD%95%E9%9D%A2%E8%AF%95%E6%8B%BF%E9%AB%98%E8%96%AA%EF%BC%81.md)對大家有一個方向參考。
[外鍊圖檔轉存中…(img-LgdJXWl9-1646387697902)]