1. 程式人生 > >利用MAT進行記憶體洩露分析

利用MAT進行記憶體洩露分析

前言

對於程式設計師來說碼程式碼容易,保證程式碼的穩定性很難。有時候寫完一個功能可能只需要一天時間,但是這個功能隱藏的bug導致的線上問題排查可能需要一週或者更長時間。因此,擁有良好的程式碼結構和編碼規範是一個程式設計師應該長期堅持併為之奮鬥的一個目標。但是,百密也難免一疏,沒有百分之百沒有問題的程式碼,在產品上線前,我們需要對自己的程式碼進行充分的自測,發現問題解決問題,保證自己產品的穩定性並減少對使用者的困擾。今天,就給大家簡單介紹一下如何使用MAT(Memory Analyzer Tools)進行Android記憶體洩漏分析,目前這類文章已經很多,我只是拋磚引玉,希望大家能夠將這個強大的工具靈活使用起來。

MAT簡介

MAT是一款非常強大的記憶體分析工具,在Eclipse中有相應的外掛,同時也有單獨的安裝包。在進行記憶體分析時,只要獲得了反映當前裝置記憶體映像的hprof檔案,通過MAT開啟就可以直觀地看到當前的記憶體資訊。一般說來,這些記憶體資訊包含:

  • 所有的物件資訊,包括物件例項、成員變數、儲存於棧中的基本型別值和儲存於堆中的其他物件的引用值。
  • 所有的類資訊,包括classloader、類名稱、父類、靜態變數等
  • GCRoot到所有的這些物件的引用路徑
  • 執行緒資訊,包括執行緒的呼叫棧及此執行緒的執行緒區域性變數(TLS)

MAT支援將這些資訊通過我們需要的方式歸納和顯示,這樣,整個記憶體資訊就一覽無餘地顯示在了我們的面前。
雖然MAT有如此強大的功能,但是記憶體分析也沒有簡單到一鍵完成的程度,很多記憶體問題還是需要我們從MAT展現給我們的資訊當中通過經驗和直覺來判斷才能發現。下面,我們就先介紹一下MAT的一些功能。

Overview

用MAT開啟一個hprof檔案後一般會進入如下的overview介面,或者和這個介面類似的leak suspect介面,overview介面會以餅圖的方式顯示當前消耗記憶體最多的幾類物件,可以使我們對當前記憶體消耗有一個直觀的印象。但是,除非你的程式記憶體洩漏特別明顯或者你正好在生成hprof檔案之前復現了程式的記憶體洩漏場景,你才可能通過這個介面猜到程式出問題的地方。
overview

Dorminator Tree(支配樹)

支配樹可以直觀地反映一個物件的retained heap,這裡我們首先要了解兩個概念,shallow heap和retained heap:

  • shallow heap:指的是某一個物件所佔記憶體大小。
  • retained heap:指的是一個物件的retained set所包含物件所佔記憶體的總大小。

retained set指的是這個物件本身和他持有引用的物件和這些物件的retained set所佔記憶體大小的總和,用官方的一張圖來解釋如下:

retained set

雖然說MAT定義的支配樹和上圖中的引用樹稍有不同,但是二者的本質都可以反映一個物件如果被回收,有多少記憶體可以同時得到釋放,只不過支配樹的定義下可以更精確地反映這個數量。如果你感興趣,可以繼續看我之後的對支配樹的概念解釋,如果一時理解不過來可以跳過,把支配樹簡單想象成引用樹即可。
實際上支配樹就是從引用樹演化而來。所謂支配,例如x物件支配y物件,就是在引用樹當中,一條到y的路徑必然會經過x;所謂直接支配,例如x直接支配y,指的是在所有支配y的物件中,x是y最近的一個物件。支配樹就是反映的這種直接支配關係,在支配樹種,父節點必然是子節點的直接支配物件,下圖就是一個從引用樹到支配樹的轉換示意圖:

dorminator tree

上面這幅圖右邊就是從左邊轉換而來形成的支配樹,這裡特別對C節點形成的子樹做一下說明。CDE及DF、EG的關係就不用多說,從引用樹和我們剛才對支配概念的闡述可以直接得出結論,關鍵是H節點,H節點在支配樹種既不是D的子節點也不是E的子節點是因為,在引用樹當中,能夠到達H的路徑有兩條,DEFG節點都不是到達它的路徑上必須經過的節點,符合這個條件的只有C節點,因此在支配樹中H是C的子節點。現在仔細觀察支配樹可以發現,一個節點的子樹正好就是這個節點對應的retained set。比如,如果D節點被回收,那麼就可以釋放DF物件所佔的記憶體,但是H所佔的記憶體還不能得到釋放,因為可能G還在引用著H,這也是為什麼在支配樹中H是C節點的子節點的原因,只有C節點被回收了才一定能夠回收H節點所佔的記憶體。
說了這麼多,MAT中Dorminator Tree到底能夠用到什麼上面?我認為,它主要可以用於診斷一個物件所佔記憶體為什麼會不斷膨脹,一個物件膨脹,就說明它對應到支配樹中的子樹就越來越龐大,只要分析這個物件對應的子樹,確定那些物件是不應該出現在子樹中就可以對問題手到病除。下面舉一個例項進行簡單分析。
在android中ListView物件是可以不斷對其子view進行服用來達到提高記憶體使用效率的目的,ListView的這一特性依賴於List Adapter的getView的實現,我們通過如下程式碼來故意使ListView無法服用其子view,從而模擬物件膨脹的情況,程式碼如下:

public class LeakedListviewExample extends Activity {
    private ListView mLeakedListview;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.leaked_listview);
        mLeakedListview = (ListView) findViewById(R.id.leaked_listview);
        mLeakedListview.setAdapter(new LeakedAdapter());
    }
    private class LeakedAdapter extends BaseAdapter {
        @Override
        public int getCount() {
            return 1000;
        }
        @Override
        public Object getItem(int position) {
            return String.valueOf(position);
        }
        @Override
        public long getItemId(int position) {
            return position;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // 不復用convertView,每次都new一個新的物件
            TextView leakedView = new TextView(LeakedListviewExample.this);
            leakedView.setText(String.valueOf(position));
            return leakedView;
        }
    }
}   

在執行程式碼的裝置多次上下滑動這個ListView後,可以觀察這個應用程式所佔記憶體越來越大,每次手動GC後效果也不明顯,說明出現了記憶體洩漏的現象,於是我們通過MAT dump出記憶體,切換到Dorminator Tree後可以看到如下的情況:

leaked dorminator tree

首先就可以看到ListView的shallow heap和retained heap是非常不成比例的,這說明這個ListView持有了大量物件的引用,正常情況下ListView是不會出現此現象。於是我們根據retained heap的大小逐步對ListView的支配樹進行展開可以發現,Recycle Bin下面持有大量的TextView的引用,數量高達2500多個,而在正常情況下,ListView會複用Recycle Bin當中type型別相同的view,其中的物件個數不可能如此龐大,因此,從這裡就可以斷定ListView使用不當出現了記憶體洩漏。

Histogram

以直方圖的方式來顯示當前記憶體使用情況可能更加適合較為複雜的記憶體洩漏分析,它預設直接顯示當前記憶體中各種型別物件的數量及這些物件的shallow heap和retained heap。結合MAT提供的不同顯示方式,往往能夠直接定位問題,還是以上面的程式碼為例,當我們切換到histogram檢視下時,可以看到:

histogram

根據retained heap進行排序後可見,TextView存在2539個物件,消耗的記憶體也比較靠前,由於TextView屬於佈局中的元件,一般來說應用程式介面不能複雜到有這麼多的TextView的存在,因此這其中必定存在問題。那麼又如何來確定到底是誰在持有這些物件而導致記憶體沒有被回收呢?有兩種方式,第一就是右鍵選擇List Objects -> with incoming reference,這可以列出所有持有這些TextView物件的引用路徑,如圖

incoming reference

從中可以看出幾乎所有的TextView物件都被ListView持有,因此基本可以斷定出現了ListView沒有複用view的情況;第二種方式就更直接粗暴,但是非常有效果,那就是藉助我們剛才說的dorminator tree,右鍵選擇Immediate Dorminator後就可以看到如下結果

immediate dorminator

從中可以看到,有2508個TextView物件都被ListView的RecycleBin持有,原因自然就很明確了。

MAT的查詢選項

上面主要介紹的是MAT的兩個結果分析介面,其實,配合不同的查詢選項,可以將它們的威力最大化。MAT中常用的查詢選項集合都在頂部以圖示的方式進行了顯示

queries tool bar

從左到右依次為:顯示Overview檢視,顯示Histogram檢視,顯示Dorminator Tree檢視,使用OQL語言對結果進行查詢,顯示執行緒資訊,結果智慧分析,自定義查詢選項集合,根據地址查詢物件,結果分組,計算retained heap等。前三項就不再多說,分別對應之前我們介紹的三個結果分析結果顯示方式,剩餘的我挑選一些常用的選項結合一些例項進行說明。

OQL(Object Query Language)

在MAT中支援物件查詢語句,這是一個類似於SQL語句的查詢語言,能夠用來查詢當前記憶體中滿足指定條件的所有的物件。OQL將記憶體中的每一個不同的類當做一個表,類的物件則是這表中的一條記錄,每個物件的成員變數則對應著表中的一列。
OQL的基本語法和SQL相似,語句的基本組成如下

SELECT * FROM [ INSTANCEOF ] <class name="name"> [ WHERE <filter-expression> ] </filter-expression></class>

所以,當你輸入

select * from instanceof android.app.Activity

的時候,就會將當前記憶體中所有Activity及其之類都顯示出來。但是OQL也有一些特別的用法。下面簡單介紹一下OQL各部分的基本組成(更詳細的可以參看這裡)。

FROM部分

首先是OQL的from部分,指明瞭需要查詢的物件,可以是如下的這些型別:

  • 一個類的完整名稱,例如

    select * from com.example.leakdemo.LisenerLeakedActivity
    
  • 正則表示式,例如

    SELECT * FROM "java\.lang\..*"
    
  • 基本型別陣列或者物件陣列,例如int[]或者java.io.File[]

    select * from java.io.File[]
    
  • 物件的地址,例如0x2b7468c8

    select * from 0x2b7468c8, 0x2b7468dd
    
  • 物件的id,例如20815

    select * from 66888
    
  • 甚至可以是另外一個OQL的查詢結果,以實現級聯查詢。

    SELECT * FROM (SELECT * FROM java.lang.Class c WHERE c implements org.eclipse.mat.snapshot.model.IClass )
    

from部分還可以用如下兩個關鍵詞進行修飾

  • INSTANCEOF : 用來包含查詢指定類的子類進行查詢,否則只查詢和from部分完全匹配的類,例如:

    SELECT * FROM INSTANCEOF android.app.Activity
    
  • OBJECTS : 修飾後最多隻會返回一條結果,指明查詢結果對應的類資訊,而不是物件資訊,例如:

    SELECT * FROM OBJECTS com.example.leakdemo.LisenerLeakedActivity
    

    返回的就是LisenerLeakedActivity對應的類的資訊,而不是記憶體中存在的ListenerLeakedActivity物件。

from部分還能為查詢指定別名,以便提高可讀性。例如

SELECT result.mType FROM OBJECTS com.example.leakdemo.LisenerLeakedActivity result

這裡的result即是我們指定的別名,在我們不指定的情況下OQL預設別名為空,如下語句和上面語句效果是相同的

SELECT .mType FROM OBJECTS com.example.leakdemo.LisenerLeakedActivity
SELECT部分

這部分和WHERE部分只最靈活也是最複雜的部分,但是大部分情況下我認為在這裡使用“*”最好,因為一般這樣我們的結果裡面的資訊是最全。不過如果你不想被結果中的其他資訊干擾,可以自定義這部分的內容來實現。
OQL可以通過自定義select來實現對記憶體中物件或者類的各種屬性及方法結果等進行查詢,這主要通過以下三種表達方式來實現。

  • 訪問查詢物件的屬性的表示式為:

    [ <alias>. ] <field> . <field>. <field>
    

    其中alias代表別名,是在from部分中定義的,可以省略;field就是物件中定義的屬性。這種方式能夠訪問到查詢物件的屬性值,例如:

    SELECT result.mType FROM OBJECTS com.example.leakdemo.LisenerLeakedActivity result
    

    能夠展現出LisenerLeakedActivity.mType組成的查詢結果。

  • 查詢訪問Java Bean及該物件在MAT中的屬性,需要的表示式為:

    [ <alias>. ] @<attribute> 
    

    通過這種方式能夠查詢到的內容比較多,我們可以通過使用MAT中對OQL的自動補全功能(點這裡檢視)來選擇需要查詢的內容,例如:

    SELECT [email protected] AS "class", [email protected] AS "display name" FROM com.example.leakdemo.LisenerLeakedActivity result  
    

    就可以得到物件對應的class資訊和物件在heap dump中的顯示名稱。

  • 查詢訪問一些底層物件的Java方法的返回結果。MAT可以通過反射來呼叫當前查詢物件的底層類的Java方法,從而得到這些方法的執行結果。其表示式為:

    [ <alias> . ] @<method>( [ <expression>, <expression> ] ) ...
    

    注意method後面的括號是必不可少的,否則OQL會認為這是一個屬性名稱。”@”符號在新版本的OQL已經可以不需要了,例如:

    SELECT [email protected](), result.getField("mType") FROM com.example.leakdemo.LisenerLeakedActivity result 
    

    可以得到當前物件是否有基類,以及物件中的mType屬性的值是多少。

不僅如此,select部分還支援很多有用的內建函式,這裡就不一一介紹了,大家可以戳這裡檢視。
關於select部分的更多資訊還可以到這裡具體檢視。

WHERE部分

靈活設定where引數可以為我們排除很大一部分的干擾資訊,這部分對於屬性和方法的支援和select部分相同,支援的運算子號和關鍵字有:

<=, >=, >, <, [ NOT ] LIKE, [ NOT ] IN, IMPLEMENTS, =, !=, AND, OR

相信大家都清楚這些關鍵值的意義,舉一個簡單例子

SELECT * FROM com.example.leakdemo.LisenerLeakedActivity result where result.mType = 1

上面那個查詢語句可以查詢到所有LisenerLeakedActivity.mType為1的物件。關於where部分的相信介紹可以參考這裡
OQL可以用來排查緩慢記憶體洩漏的情況,這種形式的記憶體洩漏只有程式長時間執行才會造成OOM,在排查階段由於洩漏不嚴重而不能夠在Dominator Tree或者Histogram中明顯表現出來,但是如果你清楚在當前階段程式中的一些重要物件的大概數量的話,則可以通過OQL來查詢驗證。這種方式對於在Android中排查Activity洩漏十分有用,例如有下面的程式碼:

public class LisenerLeakedActivity extends Activity {
    private static final String TYPE_KEY = "type_key";
    private DemoListener mListener;
    private int mType = -1;
    public static void startListenerLeakedActivity(Context context, int actiivtyType) {
        Intent intent = new Intent(context, LisenerLeakedActivity.class);
        intent.putExtra(TYPE_KEY, actiivtyType);
        context.startActivity(intent);
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mType = getIntent().getIntExtra(TYPE_KEY, -1);
        mListener = new InnerListener();
        DemoListenerManager.getInstance().registerListener(mListener);
    }
    public int getActivityType() {
        return mType;
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 故意製造洩漏
//        if (null != mListener) {
//            DemoListenerManager.getInstance().unregisterListener(mListener);
//        }
    }
    private class InnerListener implements DemoListener {
        @Override
        public void nothingToHandle() {
            // nothing to do
        }
    }
}

上面Activity會在onCreate中向DemoListenerManager註冊一個Listener,而這個Listener是Activity的內部類,因此它持有這個Activity的引用,如果在Activity的onDestroy階段沒有及時的反註冊,那麼這個Activity就洩漏了。現在隨著多次啟動和關閉這個Activity,我們可以發現gc後的記憶體總是不斷增長,這是一個記憶體洩漏的特徵,於是我們dump出當前記憶體,但是在其中的Dorminator Tree和Histogram中都不能很明確地得出問題所在,於是我們只能按照經驗使用OQL來排查。假設你對Activity的洩漏有所懷疑,通過簡單輸入:

select * from instanceof android.app.Activity

可以得到如下結果:

OQL

從結果當中可以看到,當前記憶體中存在多個ListenerLeakActivity,而按照我們的原則,離開一個Activity就應該及時銷燬和釋放改Activity的資源,因此這就說明了Activity的洩漏是造成洩漏的原因之一。

自定義查詢選項集合

這部分的功能其實和在顯示列表中點選右鍵得到的選單相同,如下所示:

context menu

下面挑選比較重要的幾個選項來說明。

List Objects

有兩個選項:with incoming refrences和with outcoming refreences,分別會羅列出選定物件在引用樹中的父節點和子節點,可以作為為什麼當前物件還保留在記憶體中的基本依據。在平時的排查過程中,此功能還是比較常用,因為可以順著羅列出的引用路徑一步步分析記憶體洩漏的具體原因,例如如下是上面Demo中針對ListenerLeakedActivity的一個with incoming reference的結果,從這個結果中可以逐步展開,最後得到是因為DemoListenerManager的單例仍然持有ListenerLeakedActivity的InnerListener造成洩漏的結論。

List Objects

注意,如果你選擇with incoming references得到的每個結果展開後仍然是針對選擇展開的內容的with incoming references,對於with outcoming references也一樣。因此,如果兩個物件存在迴圈引用,你需要仔細分析,排除迴圈引用的路徑。例如上圖中就不能再展開引用源:ListenerLeakedActivity的mListener進行分析,因為ListenerLeakedActivity本身就和InnerListner存在相互引用關係,展開就又得到了ListenerLeakedActivity的incoming references結果,和一級列表結果是一樣的,一直這樣展開下去就真是子子孫孫無窮匱也了。

Show objects by class

和List Objects相似,也可以羅列出當前選中物件在引用樹種的上下級關係,只是這個選項會將結果中型別相同的物件進行歸類,比如結果中有多個String型別的物件,List Objects會將它們分別顯示出來,而Show objects by class會將它們統一歸類為java.lang.String。雖然相對來說結果顯示簡潔了,但是我個人在平時分析的過程中一般較少使用到這個功能。

Merge Shortest Path To GC Roots

這是快速分析的一個常用功能,它能夠從當前記憶體映像中找到一條指定物件所在的到GC Root的最短路徑。這個功能還附帶了其他幾個選項,這幾個選項分別指明瞭計算最短路徑的時候是否是需要排除弱引用、軟引用及影子引用等,一般來說這三種類型的引用都不會是造成記憶體洩漏的原因,因為JVM遲早是會回收只存在這三種引用的資源的,所以在dump記憶體映像之前我們都會手動觸發一次gc,同時在找最短引用路徑的時候也會選擇上exclude all phantom/weak/soft etc. references選項,排除來自這三種引用的干擾。如下是針對ListenerLeakedActivity的一次Merge Shortest Path To GC Roots的結果,從圖中可以明顯地看到一條從sInstance->mListener->array->ListenerLeakedActivity的引用路徑,這個結果已經足以定位Demo中記憶體洩漏的原因了。

Merge Shortest Path To GC Roots

Java Basics

這個選項並不是很常用,這裡只簡單介紹一下其中的Class Loader Explorer子選項,它可以用來檢視一些和選定物件的class loader相關的特性,包括這個class loader的名稱、繼承關係和它所載入的所有型別,如果你的程式當中應用到了自定義class loader或者osgi相關的特性,這個選項會為你分析問題提供一定程度的幫助。如下是我們通過Demo中的ListenerLeakedActivity的Class Loader Explorer可以看到如下結果。結果表明ListenerLeakedActivity是由PathClassLoader載入的,同時羅列了由這個class loader載入的其他8個型別以及這些型別目前在記憶體中的例項數量。

Class Loader Explorer

Java Collections

這塊的功能平時確實少有用到,對其中的功能應用不太瞭解,大家有興趣可以參考這裡。也歡迎大家幫助我補充一下這塊的功能應用。

Immidiate Dominators

這是一個非常有用的功能,它的作用就是找出選擇物件在Dominator Tree中的父節點。根據我們之前對Dominator Tree的闡述,就是找到一個對此物件存在於記憶體中負直接責任的物件,這個方法一般和List Objects或者Merge Shortest Path To GC Roots相互結合使用,共同定位或相互佐證。因為去掉了一個節點在引用樹中的一個父節點並不一定能保證這個物件會被回收,但是如果去掉了它的Immediate Dominator,那這個物件一定會被回收掉;但同時,有時候一個物件的Immidate Dominator計算出來是GC Roots,因為它處在引用樹中的路徑沒有一個非GC Roots的共同點,這個時候我們直接用Immidiate Dominators就不太好分析,而需要藉助List Objects或者Merge Shortest Path To GC Roots的功能。因此,這幾個方法需要相互配合使用。

Show Retained Set

這個功能簡單來說就是顯示選定物件對應在Dominator Tree中的子節點集合,所有這些子節點所佔空間大小對應於它的retained heap。可以用來判斷當一個物件被回收的話有多少其他型別的物件會被同時回收掉,例如,我們上面的Demo中,因為InnerListener同時被ListenerLeakedActivity和DemoListenerManager所持有,因此它不在這兩個物件任何一個的retained set中,而是在這兩個物件的公共節點GC Roots的retained set中,但是如果我們沒有向DemoListenerManager中註冊過InnerListener,那麼它會出現在ListenerLeakedActivity的retained set中。

結果分組

這個選項支援將列表顯示的結果按照繼承關係、包名或者class loader進行分組,預設情況下我們結果顯示是不分組的,例如Histogram和Dominator Tree的查詢結果只是將對應引用樹和Dominator Tree中的各個節點羅列出來,這樣就包含了很多系統中的其他我們不關注的資訊,使用分組的方法就可以方便聚焦到我們關注的內容之中。例如,下面分別是我們對Demo的Histogram檢視結果進行按照包名和繼承關係進行分組的結果顯示。從中看到按照包名排序的方式方便我們著重關注那些我們自己實現的類在記憶體中的情況,因為畢竟一般情況下出現洩漏問題的是我們自己的程式碼;而按照繼承關係的方式進行分類我們可以直接看到當前記憶體中到底有多少個Activity的子類及其物件存在,方便我們重點排查某些類。

group by package
group by superclass

計算retained heap

在我們一開始選擇Histogram或者Dominator Tree檢視查詢結果的時候,MAT並沒有立即開始為我們計算對應各個節點的Rtained Heap大小,此時我們可以用這個功能來進行計算,以方便我們進行洩漏的判斷。這個選項又包含兩個演算法,一個是quick approx的方式,即快速估算,這個演算法特點是速度快,能夠快速計算出羅列各項Retained Heap所佔的最小記憶體,所以你用這個方式計算後看到的Rtained Heap都是帶有”>=”標誌的;如果你想精確地瞭解各項對應Retained Heap的大小,可以選擇使用Calculate Precise Retained Size,但是根據當前記憶體映像大小和複雜度的不同,計算過程耗時也不相同,但一般都比第一種方式慢得多。

結束語

還是花了不少時間來寫這篇部落格,中間參考了不少其他同行的勞動成果,也不知道是否後面能否完全一一列舉,但更多的是自己的總結。在寫這篇部落格之前自己也使用過一段MAT,但並不是每個功能都使用到了,所以如果其中有什麼地方理解有誤還望各位讀者留言指正。
關於Android記憶體洩漏檢測的一個神器LeakCanary,大家可以參考我之前寫的另外一篇部落格

參考:

相關推薦

利用MAT進行記憶體洩露分析

前言 對於程式設計師來說碼程式碼容易,保證程式碼的穩定性很難。有時候寫完一個功能可能只需要一天時間,但是這個功能隱藏的bug導致的線上問題排查可能需要一週或者更長時間。因此,擁有良好的程式碼結構和編碼規範是一個程式設計師應該長期堅持併為之奮鬥的一

Linux下利用Valgrind工具進行記憶體洩露檢測和效能分析

Valgrind通常用來成分析程式效能及程式中的記憶體洩露錯誤 一 Valgrind工具集簡紹 Valgrind包含下列工具:     1、memcheck:檢查程式中的記憶體問題,如洩漏、越界、非法指標等。     2、callgrind:檢測程式程式碼的執行

Android Studio + MAT 給你看真實專案實戰的記憶體洩露分析

先貼出我要進行實戰的專案背景;專案已經出爐快半年時間了,現在要對它進行效能上的優化,這時候就要使用到 MAT 。然後隨便記錄一下我的分析歷程。 首先要了解兩個概念:記憶體溢位和記憶體洩漏 記憶體溢位

arm linux下交叉編譯valgrind工具進行記憶體洩露檢測和效能分析

C/C++等底層語言在提供強大功能及效能的同時,其靈活的記憶體訪問也帶來了各種糾結的問題。如果crash的地方正是記憶體使用錯誤的地方,說明你人品好。如果crash的地方記憶體明顯不是consistent的,或者記憶體管理資訊都已被破壞,編譯器不能發現這些問題,.執行時才能捕獲到這些錯誤並且還是隨機出現的,那

利用python進行數據分析——histogram

python hist()DataFrame.hist(data, column=None, by=None, grid=True, xlabelsize=None, xrot=None, ylabelsize=None, yrot=None,ax=None, sharex=False, sharey=Fal

PYTHON學習(三)之利用python進行數據分析(1)---準備工作

-- 下載 rip 安裝包 png 要求 eight code 電腦   學習一門語言就是不斷實踐,python是目前用於數據分析最流行的語言,我最近買了本書《利用python進行數據分析》(Wes McKinney著),還去圖書館借了本《Python數據分析基礎教程--N

利用Python進行數據分析_Pandas_匯總和計算描述統計

描述 行數 OS 進行 weight pytho col font gpo 申明:本系列文章是自己在學習《利用Python進行數據分析》這本書的過程中,為了方便後期自己鞏固知識而整理。利用Python進行數據分析_Pandas_匯總和計算描述統計

利用Python進行數據分析——pandas入門

平均值 標準 AR 找不到 recent 位置 index 操作 基於 利用Python進行數據分析——pandas入門 基於NumPy建立的 from pandas importSeries,DataFrame,import pandas as pd 一、兩種數據

利用python進行數據分析》學習筆記--pandas(1)

索引 eight and dong 改變 組成 過濾 isnull 學習 pandas主要的兩個數據結構是:Series 和DataFrame 1、Series series 類似於一維數組,由 索引+數據組成 若不指定索引,則會自動創建0到N-1的整數型索引, 可

分享 《利用Python進行數據分析(第二版)》高清中文版PDF+英文版PDF+源代碼

pan http aid follow cee 下載 書籍 ofo 利用 《利用Python進行數據分析(第二版)》高清中文版PDF+英文版PDF+源代碼《利用Python進行數據分析(第二版)》【中文版和英文版】【高清完整版PDF】+【配套源代碼】 《利用Python進行

利用Python進行數據分析》(Wes McKinney).pdf高清版免費下載

eric 研討會 為什麽 元素 nand 層次 第6章 描述 學習 下載地址:網盤下載 備用地址:網盤下載 內容簡介 · · · · · ·【名人推薦】 “科學

分享《利用Python進行數據分析(第二版)》高清中文版PDF+高清英文版PDF+源代碼

mar cee nag 分享 bdb log 資料 cto 完整版 資料下載:https://pan.baidu.com/s/1K3DjJ9S1S3AxpacEElNF9Q 《利用Python進行數據分析(第二版)》【中文版和英文版】【高清完整版PDF】+【配套源代碼】《利

利用Python進行數據分析(第二版)》高清中文版PDF+高清英文版PDF+配套源代碼

ref 行數 watermark alt shadow href tps ado 經典 資料下載:https://pan.baidu.com/s/1K3DjJ9S1S3AxpacEElNF9Q 更多最新的資料請見:http://blog.51cto.com/3215120

Android記憶體洩露分析

一,記憶體洩露 記憶體洩露:一個不在被使用的物件被另一個存活著的物件引用,在這種情況下垃圾回收器會跳過他,因為這種引用關係足以讓該物件駐留在記憶體中,記憶體洩露是在組織垃圾回收器為未來的記憶體分配提供空間,這些洩露的物件一直佔據著記憶體,導致我們的堆記憶體空間變得更小。也加劇了垃圾回

轉載:Android 記憶體洩露分析實戰演練

版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://mp.csdn.net/postedit/82736058 轉載自任玉剛微信推文,非常全面所以記錄下來 1. 記憶體洩露簡介 記憶體洩露,即Memory Leak,指程式中不再使用到的物件因某種原因從而無法被GC正常回

利用Python進行數據分析(第2版)》高清中文版PDF+高清英文版PDF+源代碼

ces sha 對比 -m baidu tps 學習 分享 ffffff 資源鏈接:https://pan.baidu.com/s/15LtkL6q9AX-mYfPhkuXBCw《利用Python進行數據分析(第2版)》高清中文版PDF+高清英文版PDF+源代碼高清中文版P

分享《利用Python進行數據分析(第二版)》+源碼+Wes Mckinney+SeanCheney

nag vpd tps 分享 經典書籍 alt 進行 目錄 代碼 資料下載:https://pan.baidu.com/s/19WS1TkGqjJGjEQDQHG1P4A 更多資料分享:http://blog.51cto.com/14087171 《利用Python進行數據

利用Python進行數據分析PDF

工具 內容 解決 處理 ces 由於 基礎 科學計算 知識 利用Python進行數據分析PDF百度網盤鏈接:https://pan.baidu.com/s/1S6iIb69V2ap1yaoIYLVMtg 提取碼:zbeq 復制這段內容後打開百度網盤手機App,操作更方便哦內

補間動畫和屬性動畫記憶體洩露分析

在使用屬性動畫的時候,我們知道如果不在頁面結束的時候釋放掉動畫,就會引起記憶體洩露。 簡單的說就是ValueAnimator在AnimationHandler註冊自己的AnimationFrameCallback,AnimationFrameCallback介面

利用Python進行數據分析_Pandas_數據加載、存儲與文件格式

數據加載 1.2 格式 span div 逗號 names pytho spa 申明:本系列文章是自己在學習《利用Python進行數據分析》這本書的過程中,為了方便後期自己鞏固知識而整理。 1 pandas讀取文件的解析函數 read_csv 讀取帶分隔符的數據,默認分隔符