Android 內(nèi)存優(yōu)化 (1) - MAT 使用入門(mén)

本人博客地址:https://androidperformance.com
本文博客地址:https://androidperformance.com/2015/04/11/AndroidMemory-Usage-Of-MAT/

系列文章

  1. Android 內(nèi)存優(yōu)化 (1) - MAT 使用入門(mén)
  2. Android 內(nèi)存優(yōu)化之二 - MAT使用進(jìn)階
  3. Android 內(nèi)存優(yōu)化之三 - 打開(kāi) MAT 中的 Bitmap 原圖

MAT 簡(jiǎn)介

MAT(Memory Analyzer Tool),一個(gè)基于Eclipse的內(nèi)存分析工具氏捞,是一個(gè)快速碧聪、功能豐富的JAVA heap分析工具,它可以幫助我們查找內(nèi)存泄漏和減少內(nèi)存消耗液茎。使用內(nèi)存分析工具從眾多的對(duì)象中進(jìn)行分析逞姿,快速的計(jì)算出在內(nèi)存中對(duì)象的占用大小辞嗡,看看是誰(shuí)阻止了垃圾收集器的回收工作,并可以通過(guò)報(bào)表直觀的查看到可能造成這種結(jié)果的對(duì)象滞造。

MAT

當(dāng)然MAT也有獨(dú)立的不依賴(lài)Eclipse的版本欲间,只不過(guò)這個(gè)版本在調(diào)試Android內(nèi)存的時(shí)候,需要將DDMS生成的文件進(jìn)行轉(zhuǎn)換断部,才可以在獨(dú)立版本的MAT上打開(kāi)。不過(guò)Android SDK中已經(jīng)提供了這個(gè)Tools班缎,所以使用起來(lái)也是很方便的蝴光。

MAT工具的下載安裝

這里是MAT的下載地址:https://eclipse.org/mat/downloads.php,下載時(shí)會(huì)提供三種選擇的方式:

Download MAT

Update Site

這種方式后面會(huì)有一個(gè)網(wǎng)址:比如http://download.eclipse.org/mat/1.4/update-site/ 达址,安裝過(guò)Eclipse插件的同學(xué)應(yīng)該知道蔑祟,只要把這段網(wǎng)址復(fù)制到對(duì)應(yīng)的Eclipse的Install New Software那里,就可以進(jìn)行在線(xiàn)下載了沉唠。

MAT with eclipse

Archived Update Site

這種方式安裝的位置和上一種差不多疆虚,只不過(guò)第一種是在線(xiàn)下載,這一種是使用離線(xiàn)包進(jìn)行更新满葛,這種方式劣勢(shì)是當(dāng)這個(gè)插件更新后径簿,需要重新下載離線(xiàn)包,而第一種方式則可以在線(xiàn)下載更新嘀韧。

Stand-alone Eclipse RCP Applications

這種方式就是把MAT當(dāng)成一個(gè)獨(dú)立的工具使用篇亭,不再依附于Eclipse,適合不使用Eclipse而使用Android Studio的同學(xué)锄贷。這種方式有個(gè)麻煩的地方就是DDMS導(dǎo)出的文件译蒂,需要進(jìn)行轉(zhuǎn)換才可以在MAT中打開(kāi)。

下載安裝好之后谊却,就可以使用MAT進(jìn)行實(shí)際的操作了柔昼。

Android(Java)中常見(jiàn)的容易引起內(nèi)存泄露的不良代碼

使用MAT工具之前,要對(duì)Android的內(nèi)存分配方式有基本的了解炎辨,對(duì)容易引起內(nèi)存泄露的代碼也要保持敏感捕透,在代碼級(jí)別對(duì)內(nèi)存泄露的排查,有助于內(nèi)存的使用蹦魔。

Android主要應(yīng)用在嵌入式設(shè)備當(dāng)中激率,而嵌入式設(shè)備由于一些眾所周知的條件限制,通常都不會(huì)有很高的配置勿决,特別是內(nèi)存是比較有限的乒躺。如果我們編寫(xiě)的代碼當(dāng)中有太多的對(duì)內(nèi)存使用不當(dāng)?shù)牡胤剑y免會(huì)使得我們的設(shè)備運(yùn)行緩慢低缩,甚至是死機(jī)嘉冒。為了能夠使得Android應(yīng)用程序安全且快速的運(yùn)行曹货,Android的每個(gè)應(yīng)用程序都會(huì)使用一個(gè)專(zhuān)有的Dalvik虛擬機(jī)實(shí)例來(lái)運(yùn)行,它是由Zygote服務(wù)進(jìn)程孵化出來(lái)的讳推,也就是說(shuō)每個(gè)應(yīng)用程序都是在屬于自己的進(jìn)程中運(yùn)行的顶籽。一方面,如果程序在運(yùn)行過(guò)程中出現(xiàn)了內(nèi)存泄漏的問(wèn)題银觅,僅僅會(huì)使得自己的進(jìn)程被kill掉礼饱,而不會(huì)影響其他進(jìn)程(如果是system_process等系統(tǒng)進(jìn)程出問(wèn)題的話(huà),則會(huì)引起系統(tǒng)重啟)究驴。另一方面Android為不同類(lèi)型的進(jìn)程分配了不同的內(nèi)存使用上限镊绪,如果應(yīng)用進(jìn)程使用的內(nèi)存超過(guò)了這個(gè)上限,則會(huì)被系統(tǒng)視為內(nèi)存泄漏洒忧,從而被kill掉蝴韭。

常見(jiàn)的內(nèi)存使用不當(dāng)?shù)那闆r

查詢(xún)數(shù)據(jù)庫(kù)沒(méi)有關(guān)閉游標(biāo)

描述:
程序中經(jīng)常會(huì)進(jìn)行查詢(xún)數(shù)據(jù)庫(kù)的操作,但是經(jīng)常會(huì)有使用完畢Cursor后沒(méi)有關(guān)閉的情況熙侍。如果我們的查詢(xún)結(jié)果集比較小榄鉴,對(duì)內(nèi)存的消耗不容易被發(fā)現(xiàn),只有在常時(shí)間大量操作的情況下才會(huì)復(fù)現(xiàn)內(nèi)存問(wèn)題蛉抓,這樣就會(huì)給以后的測(cè)試和問(wèn)題排查帶來(lái)困難和風(fēng)險(xiǎn)庆尘。
示例代碼:

Cursor cursor = getContentResolver().query(uri ...);
   if (cursor.moveToNext()) {
   ... ... 
}

修正示例代碼:

Cursor cursor = null;
try {
   cursor = getContentResolver().query(uri ...);
   if (cursor != null && cursor.moveToNext()) {
   ... ... 
   }
   } finally {
       if (cursor != null) {
   try { 
       cursor.close();
   } catch (Exception e) {
       //ignore this
       }
   }
} 

構(gòu)造Adapter時(shí),沒(méi)有使用緩存的 convertView

描述:以構(gòu)造ListView的BaseAdapter為例芝雪,在BaseAdapter中提供了方法:

public View getView(int position, View convertView, ViewGroup parent)

來(lái)向ListView提供每一個(gè)item所需要的view對(duì)象减余。初始時(shí)ListView會(huì)從BaseAdapter中根據(jù)當(dāng)前的屏幕布局實(shí)例化一定數(shù)量的view對(duì)象,同時(shí)ListView會(huì)將這些view對(duì)象緩存起來(lái)惩系。當(dāng)向上滾動(dòng)ListView時(shí)位岔,原先位于最上面的list item的view對(duì)象會(huì)被回收,然后被用來(lái)構(gòu)造新出現(xiàn)的最下面的list item堡牡。這個(gè)構(gòu)造過(guò)程就是由getView()方法完成的抒抬,getView()的第二個(gè)形參 View convertView就是被緩存起來(lái)的list item的view對(duì)象(初始化時(shí)緩存中沒(méi)有view對(duì)象則convertView是null)。

由此可以看出晤柄,如果我們不去使用convertView擦剑,而是每次都在getView()中重新實(shí)例化一個(gè)View對(duì)象的話(huà),即浪費(fèi)資源也浪費(fèi)時(shí)間芥颈,也會(huì)使得內(nèi)存占用越來(lái)越大惠勒。ListView回收l(shuí)ist item的view對(duì)象的過(guò)程可以查看:android.widget.AbsListView.java --> void addScrapView(View scrap) 方法。

示例代碼:

public View getView(int position, View convertView, ViewGroup parent) {
 View view = new Xxx(...);
 ... ...
 return view;
}

示例修正代碼:

public View getView(int position, View convertView, ViewGroup parent) {
 View view = null;
 if (convertView != null) {
 view = convertView;
 populate(view, getItem(position));
 ...
 } else {
 view = new Xxx(...);
 ...
 }
 return view;
} 

關(guān)于ListView的使用和優(yōu)化爬坑,可以參考這兩篇文章:

  1. Using lists in Android (ListView) - Tutorial
  2. Making ListView Scrolling Smooth

Bitmap對(duì)象不在使用時(shí)調(diào)用recycle()釋放內(nèi)存

描述:有時(shí)我們會(huì)手工的操作Bitmap對(duì)象纠屋,如果一個(gè)Bitmap對(duì)象比較占內(nèi)存,當(dāng)它不在被使用的時(shí)候盾计,可以調(diào)用Bitmap.recycle()方法回收此對(duì)象的像素所占用的內(nèi)存售担。
另外在最新版本的Android開(kāi)發(fā)時(shí)赁遗,使用下面的方法也可以釋放此Bitmap所占用的內(nèi)存

Bitmap bitmap ;
 ...
 bitmap初始化以及使用
 ...
bitmap = null;

釋放對(duì)象的引用

描述:這種情況描述起來(lái)比較麻煩,舉兩個(gè)例子進(jìn)行說(shuō)明族铆。

示例A

假設(shè)有如下操作

public class DemoActivity extends Activity {
    ... ...
    private Handler mHandler = ...
    private Object obj;
    public void operation() {
     obj = initObj();
     ...
     [Mark]
     mHandler.post(new Runnable() {
            public void run() {
             useObj(obj);
            }
     });
    }
}

我們有一個(gè)成員變量 obj岩四,在operation()中我們希望能夠?qū)⑻幚韔bj實(shí)例的操作post到某個(gè)線(xiàn)程的MessageQueue中。在以上的代碼中哥攘,即便是mHandler所在的線(xiàn)程使用完了obj所引用的對(duì)象剖煌,但這個(gè)對(duì)象仍然不會(huì)被垃圾回收掉,因?yàn)镈emoActivity.obj還保有這個(gè)對(duì)象的引用逝淹。所以如果在DemoActivity中不再使用這個(gè)對(duì)象了末捣,可以在[Mark]的位置釋放對(duì)象的引用,而代碼可以修改為:

public void operation() {
    obj = initObj();
    ...
    final Object o = obj;
    obj = null;
    mHandler.post(new Runnable() {
        public void run() {
            useObj(o);
        }
    }
}

示例B

假設(shè)我們希望在鎖屏界面(LockScreen)中创橄,監(jiān)聽(tīng)系統(tǒng)中的電話(huà)服務(wù)以獲取一些信息(如信號(hào)強(qiáng)度等),則可以在LockScreen中定義一個(gè)PhoneStateListener的對(duì)象莽红,同時(shí)將它注冊(cè)到TelephonyManager服務(wù)中妥畏。對(duì)于LockScreen對(duì)象,當(dāng)需要顯示鎖屏界面的時(shí)候就會(huì)創(chuàng)建一個(gè)LockScreen對(duì)象安吁,而當(dāng)鎖屏界面消失的時(shí)候LockScreen對(duì)象就會(huì)被釋放掉醉蚁。

但是如果在釋放LockScreen對(duì)象的時(shí)候忘記取消我們之前注冊(cè)的PhoneStateListener對(duì)象,則會(huì)導(dǎo)致LockScreen無(wú)法被垃圾回收鬼店。如果不斷的使鎖屏界面顯示和消失网棍,則最終會(huì)由于大量的LockScreen對(duì)象沒(méi)有辦法被回收而引起OutOfMemory,使得system_process進(jìn)程掛掉。

總之當(dāng)一個(gè)生命周期較短的對(duì)象A妇智,被一個(gè)生命周期較長(zhǎng)的對(duì)象B保有其引用的情況下滥玷,在A的生命周期結(jié)束時(shí),要在B中清除掉對(duì)A的引用巍棱。

其他

Android應(yīng)用程序中最典型的需要注意釋放資源的情況是在Activity的生命周期中惑畴,在onPause()、onStop()航徙、onDestroy()方法中需要適當(dāng)?shù)尼尫刨Y源的情況如贷。由于此情況很基礎(chǔ),在此不詳細(xì)說(shuō)明到踏,具體可以查看官方文檔對(duì)Activity生命周期的介紹杠袱,以明確何時(shí)應(yīng)該釋放哪些資源。

使用MAT進(jìn)行內(nèi)存調(diào)試

要調(diào)試內(nèi)存窝稿,首先需要獲取HPROF文件,HPROF文件是MAT能識(shí)別的文件楣富,HPROF文件存儲(chǔ)的是特定時(shí)間點(diǎn),java進(jìn)程的內(nèi)存快照讹躯。有不同的格式來(lái)存儲(chǔ)這些數(shù)據(jù)菩彬,總的來(lái)說(shuō)包含了快照被觸發(fā)時(shí)java對(duì)象和類(lèi)在heap中的情況缠劝。由于快照只是一瞬間的事情,所以heap dump中無(wú)法包含一個(gè)對(duì)象在何時(shí)骗灶、何地(哪個(gè)方法中)被分配這樣的信息惨恭。

使用Eclipse獲取HPROF文件

這個(gè)文件可以使用DDMS導(dǎo)出,DDMS中在Devices上面有一排按鈕耙旦,選擇一個(gè)進(jìn)程后(即在Devices下面列出的列表中選擇你要調(diào)試的應(yīng)用程序的包名)脱羡,點(diǎn)擊Dump HPROF file 按鈕:

Dump HEAP with DDMS

選擇存儲(chǔ)路徑保存后就可以得到對(duì)應(yīng)進(jìn)程的HPROF文件。eclipse插件可以把上面的工作一鍵完成免都。只需要點(diǎn)擊Dump HPROF file圖標(biāo)锉罐,然后MAT插件就會(huì)自動(dòng)轉(zhuǎn)換格式,并且在eclipse中打開(kāi)分析結(jié)果绕娘。eclipse中還專(zhuān)門(mén)有個(gè)Memory Analysis視圖 脓规,得到對(duì)應(yīng)的文件后,如果安裝了Eclipse插件险领,那么切換到Memory Analyzer視圖侨舆。使用獨(dú)立安裝的,要使用Android SDK自帶的的工具(hprof-conv 位置在sdk/platform-tools/hprof-conv)進(jìn)行轉(zhuǎn)換

hprof-conv xxx.xxx.xxx.hprof xxx.xxx.xxx.hprof

轉(zhuǎn)換過(guò)后的.hprof文件即可使用MAT工具打開(kāi)了绢陌。

使用 Android Studio 獲取 HPROF 文件

使用Android Studio同樣可以導(dǎo)出對(duì)應(yīng)的HPROF文件:

Android-Studio

最新版本的Android Studio得在文件上右鍵轉(zhuǎn)換成標(biāo)準(zhǔn)的HPROF文件挨下,在可以在MAT中打開(kāi)。

MAT主界面介紹

這里介紹的不是MAT這個(gè)工具的主界面脐湾,而是導(dǎo)入一個(gè)文件之后臭笆,顯示OverView的界面。

  1. 打開(kāi)經(jīng)過(guò)轉(zhuǎn)換的hprof文件:
open hprof

如果選擇了第一個(gè)秤掌,則會(huì)生成一個(gè)報(bào)告愁铺。這個(gè)無(wú)大礙。

Leak Suspects

  1. 選擇OverView界面:
System OverView

我們需要關(guān)注的是下面的Actions區(qū)域

  • Histogram:列出內(nèi)存中的對(duì)象闻鉴,對(duì)象的個(gè)數(shù)以及大小

    Histogram
  • Dominator Tree:列出最大的對(duì)象以及其依賴(lài)存活的Object (大小是以Retained Heap為標(biāo)準(zhǔn)排序的)

Dominator Tree
  • Top Consumers : 通過(guò)圖形列出最大的object

    Top Consumers
  • Duplicate Class:通過(guò)MAT自動(dòng)分析泄漏的原因

一般Histogram和 Dominator Tree是最常用的帜讲。

MAT中一些概念介紹

要看懂MAT的列表信息,Shallow heap椒拗、Retained Heap似将、GC Root這幾個(gè)概念一定要弄懂。

Shallow heap

Shallow size就是對(duì)象本身占用內(nèi)存的大小蚀苛,不包含其引用的對(duì)象在验。

  • 常規(guī)對(duì)象(非數(shù)組)的Shallow size有其成員變量的數(shù)量和類(lèi)型決定。
  • 數(shù)組的shallow size有數(shù)組元素的類(lèi)型(對(duì)象類(lèi)型堵未、基本類(lèi)型)和數(shù)組長(zhǎng)度決定

因?yàn)椴幌馽++的對(duì)象本身可以存放大量?jī)?nèi)存腋舌,java的對(duì)象成員都是些引用。真正的內(nèi)存都在堆上渗蟹,看起來(lái)是一堆原生的byte[], char[], int[]块饺,所以我們?nèi)绻豢磳?duì)象本身的內(nèi)存赞辩,那么數(shù)量都很小。所以我們看到Histogram圖是以Shallow size進(jìn)行排序的授艰,排在第一位第二位的是byte辨嗽,char 。

Retained Heap

Retained Heap的概念淮腾,它表示如果一個(gè)對(duì)象被釋放掉糟需,那會(huì)因?yàn)樵搶?duì)象的釋放而減少引用進(jìn)而被釋放的所有的對(duì)象(包括被遞歸釋放的)所占用的heap大小。于是谷朝,如果一個(gè)對(duì)象的某個(gè)成員new了一大塊int數(shù)組洲押,那這個(gè)int數(shù)組也可以計(jì)算到這個(gè)對(duì)象中。相對(duì)于shallow heap圆凰,Retained heap可以更精確的反映一個(gè)對(duì)象實(shí)際占用的大需菊省(因?yàn)槿绻搶?duì)象釋放,retained heap都可以被釋放)专钉。

這里要說(shuō)一下的是娘荡,Retained Heap并不總是那么有效。例如我在A里new了一塊內(nèi)存驶沼,賦值給A的一個(gè)成員變量。此時(shí)我讓B也指向這塊內(nèi)存争群。此時(shí)回怜,因?yàn)锳和B都引用到這塊內(nèi)存,所以A釋放時(shí)换薄,該內(nèi)存不會(huì)被釋放玉雾。所以這塊內(nèi)存不會(huì)被計(jì)算到A或者B的Retained Heap中。為了糾正這點(diǎn)轻要,MAT中的Leading Object(例如A或者B)不一定只是一個(gè)對(duì)象复旬,也可以是多個(gè)對(duì)象。此時(shí)冲泥,(A, B)這個(gè)組合的Retained Set就包含那塊大內(nèi)存了驹碍。對(duì)應(yīng)到MAT的UI中,在Histogram中凡恍,可以選擇Group By class, superclass or package來(lái)選擇這個(gè)組志秃。

為了計(jì)算Retained Memory,MAT引入了Dominator Tree嚼酝。加入對(duì)象A引用B和C浮还,B和C又都引用到D(一個(gè)菱形)。此時(shí)要計(jì)算Retained Memory闽巩,A的包括A本身和B钧舌,C担汤,D。B和C因?yàn)楣餐肈洼冻,所以他倆的Retained Memory都只是他們本身崭歧。D當(dāng)然也只是自己。我覺(jué)得是為了加快計(jì)算的速度碘赖,MAT改變了對(duì)象引用圖驾荣,而轉(zhuǎn)換成一個(gè)對(duì)象引用樹(shù)。在這里例子中普泡,樹(shù)根是A播掷,而B(niǎo),C撼班,D是他的三個(gè)兒子歧匈。B,C砰嘁,D不再有相互關(guān)系件炉。把引用圖變成引用樹(shù),計(jì)算Retained Heap就會(huì)非常方便矮湘,顯示也非常方便斟冕。對(duì)應(yīng)到MAT UI上,在dominator tree這個(gè)view中缅阳,顯示了每個(gè)對(duì)象的shallow heap和retained heap磕蛇。然后可以以該節(jié)點(diǎn)位樹(shù)根,一步步的細(xì)化看看retained heap到底是用在什么地方了十办。要說(shuō)一下的是秀撇,這種從圖到樹(shù)的轉(zhuǎn)換確實(shí)方便了內(nèi)存分析呵燕,但有時(shí)候會(huì)讓人有些疑惑。本來(lái)對(duì)象B是對(duì)象A的一個(gè)成員再扭,但因?yàn)锽還被C引用,所以B在樹(shù)中并不在A下面霍衫,而很可能是平級(jí)。

為了糾正這點(diǎn)敦跌,MAT中點(diǎn)擊右鍵,可以L(fǎng)ist objects中選擇with outgoing references和with incoming references柠傍。這是個(gè)真正的引用圖的概念,

  • outgoing references :表示該對(duì)象的出節(jié)點(diǎn)(被該對(duì)象引用的對(duì)象)惧笛。
  • incoming references :表示該對(duì)象的入節(jié)點(diǎn)(引用到該對(duì)象的對(duì)象)。

為了更好地理解Retained Heap患整,下面引用一個(gè)例子來(lái)說(shuō)明:

把內(nèi)存中的對(duì)象看成下圖中的節(jié)點(diǎn),并且對(duì)象和對(duì)象之間互相引用各谚。這里有一個(gè)特殊的節(jié)點(diǎn)GC Roots,這就是reference chain(引用鏈)的起點(diǎn):

Paste_Image.png
Paste_Image.png

從obj1入手赴穗,上圖中藍(lán)色節(jié)點(diǎn)代表僅僅只有通過(guò)obj1才能直接或間接訪(fǎng)問(wèn)的對(duì)象。因?yàn)榭梢酝ㄟ^(guò)GC Roots訪(fǎng)問(wèn)膀息,所以左圖的obj3不是藍(lán)色節(jié)點(diǎn)般眉;而在右圖卻是藍(lán)色,因?yàn)樗呀?jīng)被包含在retained集合內(nèi)潜支。
所以對(duì)于左圖甸赃,obj1的retained size是obj1、obj2冗酿、obj4的shallow size總和埠对;
右圖的retained size是obj1、obj2已烤、obj3、obj4的shallow size總和妓羊。
obj2的retained size可以通過(guò)相同的方式計(jì)算胯究。

GC Root

GC發(fā)現(xiàn)通過(guò)任何reference chain(引用鏈)無(wú)法訪(fǎng)問(wèn)某個(gè)對(duì)象的時(shí)候,該對(duì)象即被回收躁绸。名詞GC Roots正是分析這一過(guò)程的起點(diǎn)裕循,例如JVM自己確保了對(duì)象的可到達(dá)性(那么JVM就是GC Roots),所以GC Roots就是這樣在內(nèi)存中保持對(duì)象可到達(dá)性的净刮,一旦不可到達(dá)剥哑,即被回收。通常GC Roots是一個(gè)在current thread(當(dāng)前線(xiàn)程)的call stack(調(diào)用棧)上的對(duì)象(例如方法參數(shù)和局部變量)淹父,或者是線(xiàn)程自身或者是system class loader(系統(tǒng)類(lèi)加載器)加載的類(lèi)以及native code(本地代碼)保留的活動(dòng)對(duì)象株婴。所以GC Roots是分析對(duì)象為何還存活于內(nèi)存中的利器。

MAT中的一些有用的視圖

Thread OvewView

Thread OvewView可以查看這個(gè)應(yīng)用的Thread信息:

Thread OvewView

Group

在Histogram和Domiantor Tree界面,可以選擇將結(jié)果用另一種Group的方式顯示(默認(rèn)是Group by Object)困介,切換到Group by package大审,可以更好地查看具體是哪個(gè)包里的類(lèi)占用內(nèi)存大,也很容易定位到自己的應(yīng)用程序座哩。

Group

Path to GC Root

在Histogram或者Domiantor Tree的某一個(gè)條目上徒扶,右鍵可以查看其GC Root Path:

Path to GC Root

這里也要說(shuō)明一下Java的引用規(guī)則:
從最強(qiáng)到最弱,不同的引用(可到達(dá)性)級(jí)別反映了對(duì)象的生命周期根穷。

  • Strong Ref(強(qiáng)引用):通常我們編寫(xiě)的代碼都是Strong Ref姜骡,于此對(duì)應(yīng)的是強(qiáng)可達(dá)性圈澈,只有去掉強(qiáng)可達(dá)士败,對(duì)象才被回收褥伴。
  • Soft Ref(軟引用):對(duì)應(yīng)軟可達(dá)性,只要有足夠的內(nèi)存饥臂,就一直保持對(duì)象隅熙,直到發(fā)現(xiàn)內(nèi)存吃緊且沒(méi)有Strong Ref時(shí)才回收對(duì)象核芽。一般可用來(lái)實(shí)現(xiàn)緩存,通過(guò)java.lang.ref.SoftReference類(lèi)實(shí)現(xiàn)驰坊。
  • Weak Ref(弱引用):比Soft Ref更弱拳芙,當(dāng)發(fā)現(xiàn)不存在Strong Ref時(shí)舟扎,立刻回收對(duì)象而不必等到內(nèi)存吃緊的時(shí)候悴务。通過(guò)java.lang.ref.WeakReference和java.util.WeakHashMap類(lèi)實(shí)現(xiàn)。
  • Phantom Ref(虛引用):根本不會(huì)在內(nèi)存中保持任何對(duì)象删窒,你只能使用Phantom Ref本身顺囊。一般用于在進(jìn)入finalize()方法后進(jìn)行特殊的清理過(guò)程,通過(guò) java.lang.ref.PhantomReference實(shí)現(xiàn)诚亚。

點(diǎn)擊Path To GC Roots --> with all references

Path To GC Roots

參考文檔

  1. Shallow and retained sizes
  2. MAT的wiki:http://wiki.eclipse.org/index.php/MemoryAnalyzer
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市益愈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌敏释,老刑警劉巖钥顽,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜂大,死亡現(xiàn)場(chǎng)離奇詭異蝶怔,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)澳叉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)耳高,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)所踊,“玉大人秕岛,你說(shuō)我怎么就攤上這事继薛。” “怎么了慈鸠?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵青团,是天一觀的道長(zhǎng)督笆。 經(jīng)常有香客問(wèn)我诱贿,道長(zhǎng),這世上最難降的妖魔是什么料扰? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任记罚,我火速辦了婚禮壳嚎,結(jié)果婚禮上烟馅,老公的妹妹穿的比我還像新娘。我一直安慰自己刊驴,他們只是感情好寡润,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布梭纹。 她就那樣靜靜地躺著,像睡著了一般础拨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上滔蝉,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天蝠引,我揣著相機(jī)與錄音蛀柴,去河邊找鬼。 笑死谅年,一個(gè)胖子當(dāng)著我的面吹牛融蹂,可吹牛的內(nèi)容都是我干的弄企。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼意乓,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼届良!你這毒婦竟也來(lái)了士葫?” 一聲冷哼從身側(cè)響起送悔,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤欠啤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后应狱,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體眉撵,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡纽疟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年污朽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片矾睦。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡枚冗,死狀恐怖蛇损,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情股囊,我是刑警寧澤稚疹,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布内狗,位于F島的核電站义锥,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏偎行。R本人自食惡果不足惜贰拿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一膨更、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧珍德,春花似錦、人聲如沸锈候。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)谷市。三九已至击孩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間及皂,已是汗流浹背验烧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工又跛, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留慨蓝,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓弧满,卻偏偏與公主長(zhǎng)得像庭呜,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子募谎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • MAT簡(jiǎn)介 MAT(Memory Analyzer Tool)阴汇,一個(gè)基于Eclipse的內(nèi)存分析工具,是一個(gè)快速拐纱、...
    This4U閱讀 1,135評(píng)論 0 5
  • 由于Android是為移動(dòng)設(shè)備開(kāi)發(fā)的操作系統(tǒng),我們?cè)陂_(kāi)發(fā)應(yīng)用程序的時(shí)候應(yīng)當(dāng)始終把內(nèi)存問(wèn)題充分考慮在內(nèi)揍庄。雖然Andr...
    Ten_Minutes閱讀 918評(píng)論 0 3
  • 作者:小強(qiáng) 貝聊移動(dòng)開(kāi)發(fā)部 Android工程師 1.Java內(nèi)存分配策略 Java 程序運(yùn)行時(shí)的內(nèi)存分配策略有三...
    貝聊科技閱讀 2,132評(píng)論 1 7
  • 那年冬天,他們是最普通的同事府阀,有著自己的男女朋友,過(guò)著滋潤(rùn)的小日子试浙。誰(shuí)也沒(méi)想到,有人的生活軌跡會(huì)和自己那么相似田巴,于...
    周小豬噠噠噠噠閱讀 513評(píng)論 2 2
  • 大家好,我叫鑫崽兒壹哺,V.Q聯(lián)盟聯(lián)合創(chuàng)始人之一,地道的東北女孩管宵,很榮幸能在這個(gè)大家庭與大家相識(shí)。 我是一名銀行職員箩朴,...
    娜軒閱讀 329評(píng)論 0 0