1. 程式人生 > >如何快速定位Android記憶體洩漏位置

如何快速定位Android記憶體洩漏位置

如果所有的物件都可以被順利回收就沒有本文的誕生了,舉個簡單的例子,我們在開發中經常使用單例模式,單例的靜態特性導致其生命週期同應用一樣長。有時建立單例時如果我們需要Context物件,如果傳入的是Application的Context那麼不會有問題。如果傳入的是Activity的Context物件,那麼當Activity生命週期結束時,該Activity的引用依然被單例持有,所以不會被回收,而單例的生命週期又是跟應用一樣長,這個情況就叫做記憶體洩露(Memory Leak)。它指的是當你不再需要某個例項後,但是這個物件卻仍然被引用,防止被垃圾回收(Prevent from being bargage collected)。

public class Util {
private Context mContext;
   private static Util sInstance;    private Util(Context context) {
this.mContext = context;
}
public static Util getInstance(Context context) {
if (sInstance == null) {
sInstance = new Util(context);
}
return sInstance;
}
}

圖示一程式碼

基於Android系統的裝置一般來說記憶體就不大,特別是早期的Android裝置,記憶體洩漏是很致命的,記憶體洩漏積攢到一定程度會引發記憶體溢位(OOM),如果處理不當直接導致程式崩潰退出。

二.常見記憶體洩漏

一般來說在開發中我們經常會犯下下面幾個錯誤,導致記憶體洩漏。這幾個都是前人踩坑總結出來的,非常有參考價值,至少我在排查解決記憶體洩漏的時候是這樣的。

1.單例造成的記憶體洩漏

Android的單例模式非常受開發者的喜愛,不過使用的不恰當的話也會造成記憶體洩漏。因為單例的靜態特性使得單例的生命週期和應用的生命週期一樣長,這就說明了如果一個物件已經不需要使用了,而單例物件還持有該物件的引用,那麼這個物件將不能被正常回收,這就導致了記憶體洩漏。見圖示一程式碼。

2.非靜態內部類建立靜態例項造成的記憶體洩漏

有的時候我們可能會在啟動頻繁的Activity中,為了避免重複建立相同的資料資源,在Activity內部建立了一個非靜態內部類的單例,每次啟動Activity時都會使用該單例的資料,這樣雖然避免了資源的重複建立,不過這種寫法卻會造成記憶體洩漏,因為非靜態內部類預設會持有外部類的引用,而又使用了該非靜態內部類建立了一個靜態的例項,該例項的生命週期和應用的一樣長,這就導致了該靜態例項一直會持有該Activity的引用,導致Activity的記憶體資源不能正常回收。例子如下:

public class MainActivity extends AppCompatActivity {

private static TestResource mResource = null;

   
@Override

   
protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

       
setContentView(R.layout.activity_main);

       if
(mManager == null) {

mManager = new TestResource();

       
}

//...

   
}

class TestResource {

//...

   
}

}

圖示二程式碼

3.Handler造成的記憶體洩漏

Handler的使用造成的記憶體洩漏問題應該說最為常見了,平時在處理網路任務或者封裝一些請求回撥等api都應該會藉助Handler來處理,我們經常在Activity裡面這樣定義一個私有的Handler物件並初始化,這種建立Handler的方式會造成記憶體洩漏,由於mHandler是Handler的非靜態匿名內部類的例項,所以它持有外部類Activity的引用,我們知道訊息佇列是在一個Looper執行緒中不斷輪詢處理訊息,那麼當這個Activity退出時訊息佇列中還有未處理的訊息或者正在處理訊息,而訊息佇列中的Message持有mHandler例項的引用,mHandler又持有Activity的引用,所以導致該Activity的記憶體資源無法及時回收,引發記憶體洩漏

private Handler mHandler = new Handler() {

@Override

   
public void handleMessage(Message msg) {

//...

   
}

};

4.資源未關閉造成的記憶體洩漏

對於使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等資源的使用,應該在Activity銷燬時及時關閉或者登出,否則這些資源將不會被回收,造成記憶體洩漏。

三.檢測記憶體洩漏的高效工具

從Eclipse時代走過來的開發者,以為我一要開始貼那張像**一樣的MAT記憶體模型圖或者AndroidStudio中Monitors下的實時記憶體佔用圖,又要開始分析那一條條剪不斷理還亂的記憶體引用鏈,然後費盡九牛二虎之力去查詢專案中無數的記憶體洩漏中的一個。但是,我要告訴你,你錯了。其實,以前我看到記憶體洩漏分析文章的時候也是這樣的想法,看著恐怖的MAT記憶體模型圖,覺得記憶體洩漏的排查和解決簡直是Android開發中登峰造極的技能。直到我遇到了她——LeakCanary,我才直到原來記憶體洩漏的排查和解決可以那麼的優雅。LeakCanary是Square開源了一個記憶體洩露自動探測神器 。這是專案的github倉庫地址:https://github.com/square/leakcanary  。使用非常簡單,在build.gradle中引入包依賴:

debugCompile 'com.squareup.leakcanary:leakcanary-
android:1.5'
releaseCompile 'com.squareup.leakcanary:leakcanary-
android-no-op:1.5'
testCompile 'com.squareup.leakcanary:leakcanary-
android-no-op:1.5'

在Application中的onCreate方法中增加初始化程式碼:

if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for
   // heap analysis.
   // You should not init your app in this process.
   
return;
}
LeakCanary.install(this);

整合後什麼都不用做,按照正常測試,當有記憶體洩漏發生後,應用會通過系統通知欄發出通知,點選通知就可以進入檢視記憶體洩漏的具體資訊。在這裡舉個實踐中的例子。把LeakCanary整合到專案中後,等App啟動後一會,系統通知到了,點選通知,跳轉到洩漏的詳情頁面進行檢視:

//去掉static修飾符,避免static物件引起的記憶體洩漏
private static FrameLayout fLayout;


public
MaskHeadView(Context context, AttributeSet attrs) {
super(context, attrs);
  this
.context=context;
 
initView(context);
}

private void initView(Context context2) {
view = LayoutInflater.from(context).inflate(R.layout.
mask_head_view, this);
 
fLayout=(FrameLayout) view.findViewById(R.id.
mask_container);
}

這只是個極簡單的例子,但方法是一樣的。順便提一句,其實無論是MAT工具的記憶體分析,還是AndroidStudio中自帶的分析工具亦或是LeakCanary,原理都是一樣的,都是dump java heap出來進行分析,找到洩漏的問題,只是LeakCanary幫我們把分析的工作做了罷了。

相關推薦

如何快速定位Android記憶體洩漏位置

如果所有的物件都可以被順利回收就沒有本文的誕生了,舉個簡單的例子,我們在開發中經常使用單例模式,單例的靜態特性導致其生命週期同應用一樣長。有時建立單例時如果我們需要Context物件,如果傳入的是Application的Context那麼不會有問題。如果傳入的是Activity的Context物件,那麼當

Android記憶體洩漏定位與解決

問題現象 反覆點選被測試的Android App的toolbar介面,然後返回再點選。在此重複過程中,發現到一定次數時,頁面開啟速度變慢,有時達到5s,十分影響使用者體驗。該問題涉及app所採用的webview框架的所有介面,影響面大。 初步分析 載入介面慢,一

linux下檢測和定位記憶體洩漏位置的方法

gtest:http://code.google.com/p/googletest/,可以下載最新的程式碼。下載後,可以參考gtest-1.6.0\make\Makefile寫自己的Makefile。 程式記憶體的資訊(/proc/self/smaps): VMSIZE:

[Android]Android記憶體洩漏你所要知道的一切(翻譯)

以下內容為原創,歡迎轉載,轉載請註明 來自天天部落格:http://www.cnblogs.com/tiantianbyconan/p/7235616.html Android記憶體洩漏你所要知道的一切 原文:https://blog.aritraroy.in/everything-

LeakCanary Android 記憶體洩漏分析利器 原始碼編譯配置mk檔案

LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := \ $(call all-java-files-under, src) LOCAL_SRC_

Android 記憶體洩漏問題

1. 內部類引用導致Activity的洩露     在Android中內部類的引用最常見的是handler,我們經常會這樣寫: private Handler handler = new Handler(){ @Override public void h

Android 記憶體洩漏之LeakCanary

導言: 記憶體管理是android開發效能中重要的一環,而leakCanary是Square開源框架,是一個Android記憶體洩露檢測庫,是個優秀的 記憶體洩露檢測工具,通過它大大降低oom的出現,提高app的質量 釋義: 記憶體洩漏:物件在有限生命週期內還持有引用,沒有被回

Android記憶體洩漏記憶體溢位

Android記憶體洩漏與記憶體溢位 記憶體洩漏 什麼是記憶體洩漏 記憶體洩漏的原因 記憶體洩漏檢測工具LeakCanary Java中的記憶體分配 Java中的四種引用型別 騰訊記憶體洩漏分析

Android記憶體洩漏的檢測工具——LeakCanary

    首先了解什麼是記憶體洩露 http://liuwangshu.cn/application/performance/ram-3-memory-leak.html   1Leakcancary的優勢 LeakCanary是一個視覺化的記憶體

根據記憶體洩漏位置新增斷點

_CrtSetBreakAlloc(XXX); XXX代表記憶體提示資訊中大括號中的數字。 Detected memory leaks! Dumping objects -> {98500} normal block at 0x05785AD0, 152 bytes long. Data:

Android記憶體洩漏問題分析及解決方案

大家新年好,由於工作繁忙原因,有好一段時間沒有更新博文了(當然Github是一直都有更新的),趁著年底有點放假時間,我覺得抽空更新下部落格,總結一下工作中最常見記憶體洩漏問題,也是自己之前踩過的坑,為了讓大家少走彎路,系統全面總結一下記憶體洩漏問題分析原因及尋找解決方案。 概念 首

Android 效能篇 -- 帶你領略Android記憶體洩漏的前世今生

基礎瞭解 什麼是記憶體洩漏? 記憶體洩漏是當程式不再使用到的記憶體時,釋放記憶體失敗而產生了無用的記憶體消耗。記憶體洩漏並不是指物理上的記憶體消失,這裡的記憶體洩漏是指由程式分配的記憶體但是由於程式邏輯錯誤而導致程式失去了對該記憶體的控制,使得記憶體浪費。 Java

一種定位android HAL程式碼位置的方法

一種定位android HAL程式碼位置的方法 2017年04月07日 23:33:20 feiniao8651 閱讀數:1044 背景 裝置廠商一般會在Android HAL層做自己定義的實現,但是不同廠商的路徑不同,在沒有文件的情況下,查詢對應的原始碼實現就要花費

Android記憶體洩漏查詢和解決adb shell dumpsys meminfo packagement

1.通過adb shell dumpsys meminfo packageName來檢視記憶體使用狀況 在沒有開啟應用的情況下,該命令返回的資料是這樣的: 2.開啟這個應用的MainActivity,再通過命令檢視: 可以看到打印出來很多的資訊,而對於我們檢

android 記憶體洩漏小結

什麼是記憶體洩漏 記憶體洩漏是當程式不再使用到的記憶體時,釋放記憶體失敗而產生了無用的記憶體消耗。記憶體洩漏並不是指物理上的記憶體消失,這裡的記憶體洩漏是值由程式分配的記憶體但是由於程式邏輯錯誤而導致程式失去了對該記憶體的控制,使得記憶體浪費 怎樣會導致記憶體洩漏 資源物件沒關閉

Android記憶體洩漏分析及除錯

 尊重原創作者,轉載請註明出處: 首先了解一下dalvik的Garbage Collection: 如上圖所示,GC會選擇一些它瞭解還存活的物件作為記憶體遍歷的根節點(GC Roots),比方說thread stack中的變數,JNI中的全域性變數,zygote中

Android記憶體洩漏------常見場景

記憶體管理和引用型別 記憶體洩漏的檢測流程、捕捉以及分析 1、單例造成的記憶體洩露 單例模式是非常常用的設計模式,使用單例模式的類,只會產生一個物件,這個物件看起來像是一直佔用著記憶體,但這並不意味著就是浪費了記憶體,記憶體本來就是拿來裝東西的,只要這個物件一直都被高效的利用就不能叫做洩

Android記憶體洩漏場景及解決方法

本文包括以下內容: 1. 記憶體洩漏原理 2. Android記憶體洩漏發生的情況 3. 檢測記憶體洩漏的工具、方法 4. 如何避免記憶體洩漏 更多Android面試相關請點選 - 四步準備Android面試 - Android開發概要 - 大疆提前批第一次電面

Android記憶體洩漏框架LeakCanary原始碼分析

LeakCanary原始碼分析 LeakCanary是一個記憶體洩漏檢測的框架,預設只會檢測Activity的洩漏,如果需要檢測其他類,可以使用LeakCanary.install返回的RefWatcher,呼叫RefWatcher.watch(obj)就可以

Mac Android 記憶體洩漏分析 實戰演練

虛的概念就不講了,自己去網上搜,一大堆。  這裡來一次實戰演練簡書上有一篇講解 記憶體洩漏分析 的文章,總結的很到位,由淺入深,比較全面。建議結合起來閱讀預備知識:1、Mac版 MAT 官網下載地址:  (也可以自行百度)http://www.eclipse.org/down