Android 內存泄漏

名詞解釋
內存泄漏:即memory leak。是指內存空間使用完畢后無法被釋放的現象,雖然Java有垃圾回收機制(GC),但是對于還保持著引用, 該內存不能再被分配使用,邏輯上卻已經不會再用到的對象,垃圾回收器不會回收它們。

內存溢出:即out of memory, 當你要求分配的內存超過了系統給你的內存時, 系統就會拋出out of memory的異常(每個Android能用的內存是有限的) 。比如: 當前應用只剩下4M的空間可用, 但你卻加載得到一個需要占用5M空間的圖片Bitmap對象, 就會拋出溢出的異常

常見內存泄漏場景&解決方案
1.非靜態內部類、匿名類()
非靜態內部類會持有外部類的引用,如果非靜態內部類的實例是靜態的,就會長期的維持著外部類的引用,阻止被系統回收。
解決方案是使用靜態內部類

1.1非靜態內部類
非靜態內部類(non static inner class)和 靜態內部類(static inner class)之間的區別。


如果非靜態內部類所創建的實例是靜態的,其生命周期等于應用的生命周期。非靜態內部類默認持有外部類的引用而導致外部類無法釋放,最終造成內存泄露。即外部類中持有非靜態內部類的靜態對象。?

public class MainActivity extends Activity {//非靜態內部類的靜態實例引用public static TestClass testClass = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//保證非靜態內部類的實例只有1個if (testClass == null) {testClass = new TestClass();}}// 非靜態內部類private class TestClass {//todo something}
}

當 MainActivity 銷毀時,因非靜態內部類單例的引用,testClass 的生命周期等于應用的生命周期,持有外部類 MainActivity 的引用,故 MainActivity 無法被 GC 回收,從而導致內存泄漏。

解決方案:
將非靜態內部類設置為:靜態內部類(靜態內部類默認不持有外部類的引用)
該內部類抽取出來封裝成一個單例
盡量避免非靜態內部類所創建的實例是靜態的

1.2 多線程相關的匿名內部類和非靜態內部類(繼承 Thread 類、實現 Runnable 接口、AsyncTask)
當子線程正在處理任務時,如果外部類銷毀, 由于子線程實例持有外部類引用,將使得外部類無法被垃圾回收器(GC)回收,從而造成內存泄露。?

public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);new MyThread().start();}private class MyThread extends Thread {@Overridepublic void run() {//todo someting}}
}

解決方案:

  1. 使用靜態內部類的方式,靜態內部類不默認持有外部類的引用。
  1. private static class MyThread extends Thread {@Overridepublic void run() {//todo someting}}
    

  2. 當外部類結束生命周期時(即Activity或Fragment),強制結束線程(onDestroy或onDestroyView)。使得工作線程實例的生命周期與外部類的生命周期同步。
    @Overrideprotected void onDestroy() {super.onDestroy();myThread.interrupt();}

2. Handler內存泄漏(重新理解為什么 Handler 可能導致內存泄露?)
Handler內部message是被存儲在MessageQueue中的,MessageQueue中的 Message 持有 Handler 實例的引用,有些message不能馬上被處理,存在的時間會很長,導致handler無法被回收,如果handler是非靜態的(內部類、匿名內部類),默認持有外部類的引用(如 MainActivity 實例),導致它的外部類無法被回收。

?

public class MainActivity extends Activity {private MyHandler myHandler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);myHandler = new MyHandler();new Thread() {@Overridepublic void run() {try {//執行耗時操作Thread.sleep(20000);} catch (InterruptedException e) {e.printStackTrace();}//發送消息myHandler.sendEmptyMessage(1);}}.start();}private class MyHandler extends Handler {@Overridepublic void handleMessage(Message msg) {//處理消息事件}}
}

解決方案:

  1. 使用靜態內部類+弱引用的方式,保證外部類能被回收。因為弱引用的對象擁有短暫的生命周期,在垃圾回收器線程掃描時,一旦發現了具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。
public class MainActivity extends Activity {private MyHandler myHandler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);myHandler = new MyHandler(this);new Thread() {@Overridepublic void run() {try {//執行耗時操作Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}//發送消息myHandler.sendEmptyMessage(1);}}.start();}public void test() {Log.d("TAG", "test");}private static class MyHandler extends Handler {//定義弱引用實例private WeakReference<Activity> reference;//在構造方法中傳入需持有的Activity實例public MyHandler(Activity activity) {//使用 WeakReference 弱引用持有 Activity 實例reference = new WeakReference<Activity>(activity);}@Overridepublic void handleMessage(Message msg) {//處理消息事件//調用Activity實例中的方法((MainActivity) reference.get()).test();}}
}
  1. 當外部類結束生命周期時,清空 Handler 內消息隊列。
    @Overrideprotected void onDestroy() {if (myHandler!= null) {myHandler.removeCallbacksAndMessages(null);}super.onDestroy();}

3. Context導致內存泄漏
根據場景確定使用Activity的Context還是Application的Context,因為二者生命周期不同,對于不必須使用Activity的Context的場景(Dialog),一律采用Application的Context,單例模式是最常見的發生此泄漏的場景,比如傳入一個Activity的Context被靜態類引用,導致無法回收

4. 靜態View導致泄漏
使用靜態View可以避免每次啟動Activity都去讀取并渲染View,但是靜態View會持有Activity的引用,導致無法回收。

解決方案:

盡量避免 static 成員變量引用資源耗費過多的實例(如 Context),若需引用 Context,則盡量使用Applicaiton的 Context。
使用弱引用(WeakReference) 代替強引用持有實例。
在Activity銷毀的時候將靜態View設置為null
5.資源對象未關閉導致
對于資源若在 Activity 銷毀時無及時關閉 / 注銷這些資源,則這些資源將不會被回收,從而造成內存泄漏。
如廣播、文件、Bitmap、數據庫等使用?

//對于廣播BroadcastReceiver:注銷注冊
unregisterReceiver(broadcastReceiver);//對于文件流File:關閉流
inputStream / outputStream.close();//對于數據庫游標cursor:使用后關閉游標
cursor.close();//對于圖片資源Bitmap:Android分配給圖片的內存只有8M,若1個Bitmap對象占內存較多,當它不再被使用時,應調用recycle()回收此對象的像素所占用的內存;最后再賦為null 
bitmap.recycle();
bitmap = null;// 對于動畫(屬性動畫),將動畫設置成無限循環播放setRepeatCount(ValueAnimator.INFINITE);后
// 在Activity退出時記得停止動畫
animator.cancel();

6.監聽器未關閉
很多需要register和unregister的系統服務要在合適的時候進行unregister,手動添加的listener也需要及時移除

7.集合中的對象未清理
集合用于保存對象,如果集合越來越大,不進行合理的清理,

8. WebView導致的內存泄漏(目前沒有遇到)
WebView只要使用一次,內存就不會被釋放,所以WebView都存在內存泄漏的問題。
通常的解決辦法是為WebView單開一個進程,使用AIDL進行通信,根據業務需求在合適的時機釋放掉

內存泄漏分析工具
lint
lint 是一個靜態代碼分析工具,同樣也可以用來檢測部分會出現內存泄露的代碼,平時編程注意 lint 提示的各種黃色警告即可。如:

在這里插入圖片描述

?

也可以手動檢測,在 Android Studio 中選擇 Code->Inspect Code。

在這里插入圖片描述

?

然后會彈出選擇檢測范圍

在這里插入圖片描述
點擊Ok,等待分析結果

?

在這里插入圖片描述
這個工具除了會檢測內存泄漏,還會檢測代碼是否規范、是否有沒用到的導包、可能的bug、安全問題等等。

?

Memory Profile :Memory Profile 的使用

LeakCanary :LeakCanary

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/36060.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/36060.shtml
英文地址,請注明出處:http://en.pswp.cn/news/36060.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

react如何實現數據渲染

React數據渲染是指將組件中的數據映射到頁面上&#xff0c;以展示出來。在React中&#xff0c;數據渲染通常是通過JSX和組件的state或props完成的。 JSX是一個類似HTML的語法&#xff0c;可以在其中嵌入JavaScript表達式。在JSX中&#xff0c;可以使用{}包裹JavaScript表達式&…

解決C語言中使用scanf輸入字符串導致for循環失效的問題

在C語言編程中&#xff0c;使用scanf函數輸入字符串是一項基本操作。然而&#xff0c;當我們嘗試在for循環中使用scanf輸入字符串時&#xff0c;可能會遇到意外的問題&#xff0c;導致循環無法正常執行。本文將深入探討這個問題&#xff0c;并提供解決方案&#xff0c;讓你能夠…

考公-判斷推理-定義判斷

第九節課 例題 例題 例題 例題 例題 例題 腳一滑&#xff0c;就是工傷&#xff0c;這難道不是操作不當嗎 例題 不要較真&#xff0c;公務員&#xff0c;把沒有全局觀念的人排除在公務員隊伍之外 例題 例題 下次看到不字&#xff0c;先給我畫上 例題 例題 例題 例題…

微信群聊微信機器人實現流程

1.注冊微信賬號 要使用一個微信機器人賬號來實現在微信群聊中的自動回復功能&#xff0c;你需要注冊一個專門用于機器人的微信賬號。 注冊微信機器人賬號的步驟如下&#xff1a; 下載微信&#xff1a;在手機或者電腦上下載并安裝微信應用程序。創建新賬號&#xff1a;打開微信…

力扣63.不同路徑II(動態規劃)

/*** author Limg* date 2022/08/09* 一個機器人位于一個 m x n 網格的左上角 &#xff08;起始點在下圖中標記為 “Start” &#xff09;。* 機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角&#xff08;在下圖中標記為 “Finish”&#xff09;。* 現在考慮網…

探討uniapp的生命周期問題

在uniapp中,生命周期函數分為應用生命周期函數、頁面生命周期函數和組件生命周期函數. 1應用聲明周期 應用生命周期函數只能在 App.vue 中監聽有效&#xff0c;在其他頁監聽無效。 onLaunch&#xff1a;當uni-app 初始化完成時觸發&#xff08;全局只觸發一次&#xff09;on…

鄉村振興指數與其30余個原始變量數據(2000-2022年)

鄉村振興是當下經濟學研究的熱點之一&#xff0c;對鄉村振興進行測度&#xff0c;是研究基礎。測度鄉村振興水平的學術論文廣泛發表在《數量經濟技術經濟研究》等頂刊上。整理了2000-2022年城市層面的鄉村振興指數與其30余個原始變量數據&#xff0c;供大家使用。 數據來源&…

react-spring,一個react的動畫庫的使用

介紹 React Spring 是一個 spring physics based animation library 用于 React。它可以輕松地在 React 中實現彈性、漸變等動畫效果。 使用 安裝依賴&#xff1a; 使用npm&#xff1a; npm install react-spring 使用yarn&#xff1a; yarn add react-spring 導入和使用&a…

Opencv4基于C++基礎入門筆記:OpenCV環境配置搭建

文章目錄&#xff1a; 一&#xff1a;軟件安裝 二&#xff1a;配置環境&#xff08;配置完之后重啟一下軟件&#xff09; 1.配置電腦系統環境變量 vs2012及其以下 vs2014及其以上 2.配置VS軟件環境變量 vs2012及其以下 vs2014及其以上 三&#xff1a;測試 vs2012及其…

Java 實現Rtsp 轉rtmp,hls,flv

服務支撐&#xff1a;FFmpeg srs(流媒體服務器) 整個流程是 FFmpeg 收流轉碼 推 rtmp 到流媒體服務 流媒體服務再 分發流到公網 搭建流媒體服務: 1. SRS (Simple Realtime Server) | SRS &#xff08;本例子使用的是SrS 安裝使用docker &#xff09; 2.GitHub - ZLMedi…

python菱形問題

Python類分為兩種&#xff0c;一種叫經典類&#xff0c;一種叫新式類。都支持多繼承&#xff0c;但繼承順序不同。 新式類&#xff1a;從object繼承來的類。&#xff08;如:class A(object)&#xff09;&#xff0c;采用廣度優先搜索的方式繼承&#xff08;即先水平搜索&#…

【二分答案】CF803 D

感覺之前的*1900好簡單 Problem - D - Codeforces 題意&#xff1a; 思路&#xff1a; 注意到寬度具有單調性&#xff0c;考慮二分寬度 然后限制了最大寬度&#xff0c;要使行數 < k 那么在check里貪心&#xff0c;每行選的盡可能多 考慮雙指針&#xff0c;每次選長度…

Spring MVC相關知識點

1.Spring MVC的理解&#xff1f; 首先&#xff0c;MVC模型是模型&#xff0c;視圖&#xff0c;控制器的簡寫&#xff0c;其思想核心是通過將請求處理控制&#xff0c;業務邏輯&#xff0c;數據封裝&#xff0c;數據顯示等流程節點分離的思想來組織代碼。 所以&#xff0c;MVC…

SpringBoot復習:(47)ConfigFileApplicationListener

它監聽ApplicationEnvironmentPreparedEvent和ApplicationPreparedEvent。 它會把配置文件中配置的內容注入到環境中去&#xff0c;配置文件也就生效了

融云榮獲「2023 中國數字生態通信領軍企業」獎

融云北極星如何協助開發者排查問題和預警風險&#xff1f; 8月17日直播課&#xff0c;點擊上方報名~ 由 B.P 商業伙伴主辦的“2023 數字生態大會”于 8 月 4 日在京舉行&#xff0c;融云攜數智辦公解決方案受邀參展&#xff0c;并獲“2023 中國數字生態通信領軍企業”獎。關注【…

詳解VCC、VDD、VEE、VSS

VCC、 VDD、VEE、VSS 版本一&#xff1a; 簡單說來&#xff0c;可以這樣理解&#xff1a; 一、解釋 VCC&#xff1a;Ccircuit 表示電路的意思, 即接入電路的電壓&#xff1b; VDD&#xff1a;Ddevice 表示器件的意思, 即器件內部的工作電壓&#xff1b; VSS&#xff1a;Sser…

vue3+element-plus組件下拉列表,數組數據轉成樹形數據

引入組件 可以直接在項目中引入element-plus表格組件&#xff0c;如果需要變成下拉列表樣式需要添加以下屬性&#xff1a; row-key 必填 最好給數字或唯一屬性 &#xff0c; 給每個節點設置id 不填的話 沒有辦法實現展開效果 load 這個是動態添加數據的 前提&#xff08;開啟…

使用MyEclipse如何部署Descriptor (XML)編輯器?

Descriptor (XML) Editor編輯器包含了高級的XML編輯功能&#xff0c;在本文中您將了解到這些編輯功能、Web XML編輯等&#xff0c;此功能包含在MyEclipse中可用。 MyEclipse v2023.1.2離線版下載 1. Web XML 編輯器 MyEclipse Web XML編輯器包括高級XML編輯功能&#xff0c;…

最新AI創作系統ChatGPT程序源碼+詳細搭建部署教程+微信公眾號版+H5源碼/支持GPT4.0+GPT聯網提問/支持ai繪畫+MJ以圖生圖+思維導圖生成!

使用Nestjs和Vue3框架技術&#xff0c;持續集成AI能力到系統&#xff01; 新增 MJ 官方圖片重新生成指令功能同步官方 Vary 指令 單張圖片對比加強 Vary(Strong) | Vary(Subtle)同步官方 Zoom 指令 單張圖片無限縮放 Zoom out 2x | Zoom out 1.5x新增GPT聯網提問功能、手機號注…

深入了解 Postman Test 校驗的使用方法

Postman 是一個廣泛使用的 API 開發工具&#xff0c;它允許開發人員測試 API 的各個方面&#xff0c;包括請求、響應、身份驗證等等&#xff0c;其中最常用的功能之一就是 Test 校驗。那今天就一起來看看 Postman 的 Test 校驗該如何使用。 Test 校驗是什么&#xff1f; Test…