日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

内存分析工具MAT的使用

發(fā)布時間:2025/4/16 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 内存分析工具MAT的使用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

原文鏈接:http://www.jianshu.com/p/d8e247b1e7b2

MAT簡介

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

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

MAT工具的下載安裝

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

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

Archived Update Site 這種方式安裝的位置和上一種差不多,只不過第一種是在線下載,這一種是使用離線包進(jìn)行更新,這種方式劣勢是當(dāng)這個插件更新后,需要重新下載離線包,而第一種方式則可以在線下載更新。

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

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

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

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

Android主要應(yīng)用在嵌入式設(shè)備當(dāng)中,而嵌入式設(shè)備由于一些眾所周知的條件限制,通常都不會有很高的配置,特別是內(nèi)存是比較有限的。如果我們編寫的代碼當(dāng)中有太多的對內(nèi)存使用不當(dāng)?shù)牡胤?#xff0c;難免會使得我們的設(shè)備運(yùn)行緩慢,甚至是死機(jī)。為了能夠使得Android應(yīng)用程序安全且快速的運(yùn)行,Android的每個應(yīng)用程序都會使用一個專有的Dalvik虛擬機(jī)實(shí)例來運(yùn)行,它是由Zygote服務(wù)進(jìn)程孵化出來的,也就是說每個應(yīng)用程序都是在屬于自己的進(jìn)程中運(yùn)行的。一方面,如果程序在運(yùn)行過程中出現(xiàn)了內(nèi)存泄漏的問題,僅僅會使得自己的進(jìn)程被kill掉,而不會影響其他進(jìn)程(如果是system_process等系統(tǒng)進(jìn)程出問題的話,則會引起系統(tǒng)重啟)。另一方面Android為不同類型的進(jìn)程分配了不同的內(nèi)存使用上限,如果應(yīng)用進(jìn)程使用的內(nèi)存超過了這個上限,則會被系統(tǒng)視為內(nèi)存泄漏,從而被kill掉。

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

1、查詢數(shù)據(jù)庫沒有關(guān)閉游標(biāo)

描述:程序中經(jīng)常會進(jìn)行查詢數(shù)據(jù)庫的操作,但是經(jīng)常會有使用完畢Cursor后沒有關(guān)閉的情況。如果我們的查詢結(jié)果集比較小,對內(nèi)存的消耗不容易被發(fā)現(xiàn),只有在常時間大量操作的情況下才會復(fù)現(xiàn)內(nè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}} }

2、構(gòu)造Adapter時,沒有使用緩存的 convertView

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

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

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

由此可以看出,如果我們不去使用convertView,而是每次都在getView()中重新實(shí)例化一個View對象的話,即浪費(fèi)資源也浪費(fèi)時間,也會使得內(nèi)存占用越來越大。ListView回收list item的view對象的過程可以查看: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)化,可以參考這兩篇文章:

  • Using lists in Android wth ListView - Tutorial

  • Making ListView Scrolling Smooth

3、Bitmap對象不在使用時調(diào)用recycle()釋放內(nèi)存

描述:有時我們會手工的操作Bitmap對象,如果一個Bitmap對象比較占內(nèi)存,當(dāng)它不在被使用的時候,可以調(diào)用Bitmap.recycle()方法回收此對象的像素所占用的內(nèi)存。

另外在最新版本的Android開發(fā)時,使用下面的方法也可以釋放此Bitmap所占用的內(nèi)存

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

4、釋放對象的引用

描述:這種情況描述起來比較麻煩,舉兩個例子進(jìn)行說明。

示例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);}});} }

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

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)中的電話服務(wù)以獲取一些信息(如信號強(qiáng)度等),則可以在LockScreen中定義一個PhoneStateListener的對象,同時將它注冊到TelephonyManager服務(wù)中。對于LockScreen對象,當(dāng)需要顯示鎖屏界面的時候就會創(chuàng)建一個LockScreen對象,而當(dāng)鎖屏界面消失的時候LockScreen對象就會被釋放掉。

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

總之當(dāng)一個生命周期較短的對象A,被一個生命周期較長的對象B保有其引用的情況下,在A的生命周期結(jié)束時,要在B中清除掉對A的引用。

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

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

要調(diào)試內(nèi)存,首先需要獲取HPROF文件,HPROF文件是MAT能識別的文件,HPROF文件存儲的是特定時間點(diǎn),java進(jìn)程的內(nèi)存快照。有不同的格式來存儲這些數(shù)據(jù),總的來說包含了快照被觸發(fā)時java對象和類在heap中的情況。由于快照只是一瞬間的事情,所以heap dump中無法包含一個對象在何時、何地(哪個方法中)被分配這樣的信息。

使用Eclipse獲取HPROF文件

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

選擇存儲路徑保存后就可以得到對應(yīng)進(jìn)程的HPROF文件。eclipse插件可以把上面的工作一鍵完成。只需要點(diǎn)擊Dump HPROF file圖標(biāo),然后MAT插件就會自動轉(zhuǎn)換格式,并且在eclipse中打開分析結(jié)果。eclipse中還專門有個Memory Analysis視圖 ,得到對應(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)換過后的.hprof文件即可使用MAT工具打開了。

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

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

MAT主界面介紹

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

打開經(jīng)過轉(zhuǎn)換的hprof文件:

如果選擇了第一個,則會生成一個報(bào)告。這個無大礙。

選擇OverView界面:

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

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

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

Top Consumers : 通過圖形列出最大的object

Duplicate Class:通過MAT自動分析泄漏的原因

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

MAT中一些概念介紹

要看懂MAT的列表信息,Shallow heap、Retained Heap、GC Root這幾個概念一定要弄懂。

Shallow heap

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

  • 常規(guī)對象(非數(shù)組)的Shallow size有其成員變量的數(shù)量和類型決定。
  • 數(shù)組的shallow size有數(shù)組元素的類型(對象類型、基本類型)和數(shù)組長度決定

因?yàn)椴幌馽++的對象本身可以存放大量內(nèi)存,java的對象成員都是些引用。真正的內(nèi)存都在堆上,看起來是一堆原生的byte[], char[], int[],所以我們?nèi)绻豢磳ο蟊旧淼膬?nèi)存,那么數(shù)量都很小。所以我們看到Histogram圖是以Shallow size進(jìn)行排序的,排在第一位第二位的是byte,char 。

Retained Heap

Retained Heap的概念,它表示如果一個對象被釋放掉,那會因?yàn)樵搶ο蟮尼尫哦鴾p少引用進(jìn)而被釋放的所有的對象(包括被遞歸釋放的)所占用的heap大小。于是,如果一個對象的某個成員new了一大塊int數(shù)組,那這個int數(shù)組也可以計(jì)算到這個對象中。相對于shallow heap,Retained heap可以更精確的反映一個對象實(shí)際占用的大小(因?yàn)槿绻搶ο筢尫?#xff0c;retained heap都可以被釋放)。

這里要說一下的是,Retained Heap并不總是那么有效。例如我在A里new了一塊內(nèi)存,賦值給A的一個成員變量。此時我讓B也指向這塊內(nèi)存。此時,因?yàn)锳和B都引用到這塊內(nèi)存,所以A釋放時,該內(nèi)存不會被釋放。所以這塊內(nèi)存不會被計(jì)算到A或者B的Retained Heap中。為了糾正這點(diǎn),MAT中的Leading Object(例如A或者B)不一定只是一個對象,也可以是多個對象。此時,(A, B)這個組合的Retained Set就包含那塊大內(nèi)存了。對應(yīng)到MAT的UI中,在Histogram中,可以選擇Group By class, superclass or package來選擇這個組。

為了計(jì)算Retained Memory,MAT引入了Dominator Tree。加入對象A引用B和C,B和C又都引用到D(一個菱形)。此時要計(jì)算Retained Memory,A的包括A本身和B,C,D。B和C因?yàn)楣餐肈,所以他倆的Retained Memory都只是他們本身。D當(dāng)然也只是自己。我覺得是為了加快計(jì)算的速度,MAT改變了對象引用圖,而轉(zhuǎn)換成一個對象引用樹。在這里例子中,樹根是A,而B,C,D是他的三個兒子。B,C,D不再有相互關(guān)系。把引用圖變成引用樹,計(jì)算Retained Heap就會非常方便,顯示也非常方便。對應(yīng)到MAT UI上,在dominator tree這個view中,顯示了每個對象的shallow heap和retained heap。然后可以以該節(jié)點(diǎn)位樹根,一步步的細(xì)化看看retained heap到底是用在什么地方了。要說一下的是,這種從圖到樹的轉(zhuǎn)換確實(shí)方便了內(nèi)存分析,但有時候會讓人有些疑惑。本來對象B是對象A的一個成員,但因?yàn)锽還被C引用,所以B在樹中并不在A下面,而很可能是平級。

為了糾正這點(diǎn),MAT中點(diǎn)擊右鍵,可以List objects中選擇with outgoing references和with incoming references。這是個真正的引用圖的概念,

outgoing references :表示該對象的出節(jié)點(diǎn)(被該對象引用的對象)。
incoming references :表示該對象的入節(jié)點(diǎn)(引用到該對象的對象)。
為了更好地理解Retained Heap,下面引用一個例子來說明:

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

從obj1入手,上圖中藍(lán)色節(jié)點(diǎn)代表僅僅只有通過obj1才能直接或間接訪問的對象。因?yàn)榭梢酝ㄟ^GC Roots訪問,所以左圖的obj3不是藍(lán)色節(jié)點(diǎn);而在右圖卻是藍(lán)色,因?yàn)樗呀?jīng)被包含在retained集合內(nèi)。
所以對于左圖,obj1的retained size是obj1、obj2、obj4的shallow size總和;
右圖的retained size是obj1、obj2、obj3、obj4的shallow size總和。
obj2的retained size可以通過相同的方式計(jì)算。

GC Root

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

MAT中的一些有用的視圖

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

Group

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

Path to GC Root

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

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

  • Strong Ref 強(qiáng)引用
    通常我們編寫的代碼都是Strong Ref,于此對應(yīng)的是強(qiáng)可達(dá)性,只有去掉強(qiáng)可達(dá),對象才被回收。
  • Soft Ref 軟引用
    對應(yīng)軟可達(dá)性,只要有足夠的內(nèi)存,就一直保持對象,直到發(fā)現(xiàn)內(nèi)存吃緊且沒有Strong Ref時才回收對象。一般可用來實(shí)現(xiàn)緩存,通過java.lang.ref.SoftReference類實(shí)現(xiàn)。
  • Weak Ref 弱引用
    比Soft Ref更弱,當(dāng)發(fā)現(xiàn)不存在Strong Ref時,立刻回收對象而不必等到內(nèi)存吃緊的時候。通過java.lang.ref.WeakReference和java.util.WeakHashMap類實(shí)現(xiàn)。
  • Phantom Ref 虛引用
    根本不會在內(nèi)存中保持任何對象,你只能使用Phantom Ref本身。一般用于在進(jìn)入finalize()方法后進(jìn)行特殊的清理過程,通過 java.lang.ref.PhantomReference實(shí)現(xiàn)。

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

擴(kuò)展閱讀

http://www.2cto.com/os/201409/335118.html

http://mikewang.blog.51cto.com/3826268/1254306/

總結(jié)

以上是生活随笔為你收集整理的内存分析工具MAT的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 小宝贝真紧h军人h | 中文字幕在线一区二区三区 | 欧美h在线观看 | 国产乱子轮xxx农村 岛国久久久 | 亚洲高清视频一区二区 | 精品乱子伦 | av大西瓜 | 日韩女优在线播放 | 一区二区黄色 | 国产99久久久欧美黑人 | 国产欧美日韩一区 | 激情另类视频 | 久久久久久久麻豆 | 欧美人与禽猛交乱配 | 亚洲午夜精品一区二区三区他趣 | 国产一级久久久 | 欧美一级网 | 亚洲国产视频一区 | 国产色无码精品视频国产 | 亚洲涩涩网 | 国产精品免费看片 | 成年人黄视频 | 久久精品波多野结衣 | 国产小视频在线 | 不卡中文字幕在线 | 上原亚衣av一区二区三区 | 一本色道久久88综合日韩精品 | 日本黄页视频 | 中国 免费 av | 亚洲视频在线观看一区二区 | 在线黄色观看 | 日本xx视频免费观看 | 在线观看wwww | 亚洲av无码国产综合专区 | 捆绑调教视频网站 | 五月天福利视频 | 国产原创剧情av | 伊人色综合久久久 | 6080成人 | 黄色激情av | 精品少妇无码av无码专区 | 日日爽视频 | 长篇高h乱肉辣文 | 4虎最新网址 | 精人妻无码一区二区三区 | 僵尸叔叔在线观看国语高清免费观看 | 久久久久久久久久久网站 | 亚欧美精品 | 日韩成人在线网站 | 国产精品粉嫩 | 精品人妻在线播放 | 日韩一级av毛片 | 国产欧美123| 呦呦视频在线观看 | 免费av网站在线观看 | 亚洲色图 欧美 | 香蕉视频传媒 | 一本色道久久88综合无码 | 久久久艹 | 日韩精品理论 | 欧美乱轮视频 | 亚洲黄视频 | 手机在线观看av片 | 久久国产精品无码一级毛片 | 中文在线亚洲 | a一级免费视频 | 欧美xxxx黑人| 中文久久字幕 | 亚洲视频在线免费 | 天天综合网入口 | 国产国语videosex另类 | 久久中文在线 | 欧美性猛交aaaa片黑人 | www色综合| jlzzjlzz亚洲女人18 | 尤物精品 | 四虎精品永久在线 | 国产日批视频在线观看 | 色盈盈影院 | av网址观看 | 九九自拍 | 波多野吉衣一区二区 | 欧美日韩操 | 超碰在线伊人 | 丁香啪啪综合成人亚洲 | 日韩免费淫片 | 久久综合干 | 国产裸体舞一区二区三区 | 久久久一二三四 | 波多野结衣之双调教hd | 三级视频网站在线观看 | 亚洲第一视频在线播放 | 嫩草一二三| 中国新婚夫妻性猛交 | 一区二区黄色 | 风流少妇一区二区三区91 | 538任你躁在线精品免费 | 第四色在线视频 | 亚洲精品在线电影 |