Android記憶體流失分析實戰,android泄漏實戰

來源:互聯網
上載者:User

Android記憶體流失分析實戰,android泄漏實戰
記憶體流失簡介

java可以保證當沒有引用指向對象的時候,對象會被記憶體回收行程回收,與c語言自己申請的記憶體自己釋放相比,java程式員輕鬆了很多,但是並不代表java程式員不用擔心記憶體流失。當java程式發生記憶體流失的時候往往具有隱蔽性。因此要藉助一些專業的平台資源去保證安全性,例如可以通過加密實現。

定義

引用百度百科的定義:“用動態儲存裝置分配函數動態開闢的空間,在使用完畢後未釋放,結果導致一直佔據該記憶體單元。直到程式結束”。從程式猿的角度來看“記憶體流失”,其實就是一個對象的生命週期超出了程式員所預期的長度(就叫它“該死不死”吧!),那麼這個對象就泄漏了。

android開發中的記憶體流失

android應用程式本身系統分配的記憶體很少,一旦發生泄漏,程式很快就會變得非常卡頓,直至OOM崩潰。接下來將通過一個案例(只是為了分析記憶體流失而設計的玩具程式,切勿模仿)來介紹記憶體流失分析工具MAT,以及記憶體分析的技巧。

公欲善其事,先利其器

準備記憶體流失的分析工具,可以安裝eclipse外掛程式mat。如果eclise安裝mat不成功,那可能是缺少必要的libs,如果嫌找庫麻煩,可以只勾選第二項安裝,不過會缺少某些功能,但是也夠用了。 
線上安裝:http://download.eclipse.org/mat/1.4/update-site/ 
下載安裝:http://mirror.hust.edu.cn/eclipse//mat/1.4/MemoryAnalyzer-1.4.0.201406041413.zip

mat外掛程式如何使用

如果已經成功安裝好了mat工具,使用起來非常簡單,首先將需要分析的應用程式跑起來,開啟eclipse的devices視圖你將會看到點擊“Dump Hprof file”按鈕,注意點擊一下就可以了,然後等待(等待幾秒)dump一個記憶體快照出來,接下來就會自動開啟mat的視圖了,如果mat沒有安裝成功,會讓你儲存一個.hprof檔案到本地。看看下面的圖例吧

dump hprof啟動mat工具

人為製造一個記憶體流失

自訂一個ActivityManager,提供兩個方法,分別用來註冊與反註冊Activity。源碼下載

public class ActivityManager {    private List<Activity> mActivities = new ArrayList<>();    private static ActivityManager sInstance;    private ActivityManager() {    };    public static ActivityManager instance() {        if (sInstance == null) {            sInstance = new ActivityManager();        }        return sInstance;    }    public void registActivity(Activity activity) {        mActivities.add(activity);    }    public void unRigistActivity(Activity activity) {        mActivities.remove(activity);    }}

在MainActivity的onCreate與onDestroy中分別調用registActivity和registActivity方法進行註冊與反註冊。但是OtherActivity卻只是註冊了,而忘記了反註冊。

public class MainActivity extends Activity {    public static final String TAG = MainActivity.class.getSimpleName();    private Button mBtn;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mBtn = (Button) findViewById(R.id.btn);        mBtn.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                Intent intent = new Intent();                intent.setClass(MainActivity.this, OtherActivity.class);                startActivity(intent);            }        });                ActivityManager.instance().registActivity(this);    }    @Override    protected void onDestroy() {        super.onDestroy();                ActivityManager.instance().registActivity(this);    }public class OtherActivity extends Activity {    public static final String TAG = OtherActivity.class.getSimpleName();    private Object[] mObjs = new Object[10000];//類比快速消耗記憶體,使效果明顯    private Button mBtn;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_other);        mBtn = (Button) findViewById(R.id.btn);        mBtn.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                for (int i = 0; i < mObjs.length; i++) {                    mObjs[i] = new Object();                }                                finish();            }        });        ActivityManager.instance().registActivity(this);    }    @Override    protected void onDestroy() {        super.onDestroy();    }}

案例中的記憶體流失是人為構造的,所以我們事先已經知道有泄漏了,但是實際的開發過程中,記憶體流失是隱形,一開始我們並不知道,所以我們需要通過一些手段來測試APP是否有記憶體流失。首先在Devices視圖中選中需要測試的進程,然後點擊Device視圖面板的Update Heap按鈕,然後開啟Heap視圖,點擊Cause GC。然後反覆的在MainActivyt和OtherActivity之間切換。觀察Heap size的變化。你會發現記憶體一直在增加。沒有穩定下來的趨勢。這個時候你就有理由懷疑記憶體流失了。

Update heap觀察heap size等變化情況

找出泄漏的對象

按照前面mat的使用步驟,dump一個記憶體快照出來,然後從分析報告中點擊“Leak suspects”這裡會列車可能泄漏的對象,其中你會發現“ com.vjson.leaks.OtherActivity”的身影。OtherActivity這個類有33個執行個體,作為代碼的生產者,你應該一下子就會發現,原來是OtherActivity泄漏了。發現它泄漏之後,如何找出是哪一個對象持有了OtherActivity對象的引用呢?

可能泄漏的報告

找出引用鏈

使用OQL物件查詢語言查詢出泄漏的對象,寫過SQL的同學一定對她有一種既陌生又熟悉的感覺,和SQL非常相似,文法簡單易懂,但是非常強大select *from com.vjson.leaks.OtherActivity賽選出OtherActivity這一類對象,然後選擇“exclude weak/soft references”賽選出除了軟引用和弱引用之外的對象,也就是強引用了!。對象的參考型別不在本文的講解範圍,但是你一定要知道“強引用”,“軟引用”,“弱引用”。“幽靈引用”,如果不知道自行腦補去吧!

OQL物件查詢找出引用鏈

對象引用鏈

然後找出GC的根節點,從圖二種可以看出,原來Activity對象被ActivityManager裡面的ArrayList給hold住了,所以接下來的工作就是在OtherActivity的onDestroy中反註冊,記憶體流失就被解決了。

Android開發中常見的記憶體流失對象沒有反註冊資料庫cursor沒有關閉Bitmap沒有回收ListView item沒有複用Handler在Activity中定義為非static的匿名內部類總結

如果耐心的看完本文,那麼恭喜你媽媽再也不用擔心記憶體流失了。其實只要掌握了分析問題的技巧與工具,記憶體流失so easy。文章中只是簡單的介紹了工具與技巧,這其中還有很多技巧需要自己去摸索。 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.