版權聲明:本文為LooperJing原創文章,轉載請注明出處!
Allaction Tracing是追蹤內存分配的工具,可以很直觀的看到某個操作是如何一步步分配的。在Android性能優化第(二)篇---Memory Monitor檢測內存泄露最后一點有簡要提到過,現在具體研究一下,廢話不多說,貼一下代碼,我對這段代碼進行內存分配追蹤。
public class LoginActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClick(View view) {
Intent intent=new Intent(this,HomeActivity.class);
startActivity(intent);
}
}
public class HomeActivity extends AppCompatActivity {
private ArrayList<User> mUserList = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
createObject();
}
private void createObject() {
mUserList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
User user = new User("wang" + i, 18 + i);
mUserList.add(user);
}
}
}
很簡單,就是用戶點擊登錄按鈕跳轉到主頁,我們需要做的,就是用戶點擊登錄按鈕的這個操作,內存發生了哪些變化。
一、啟動方式一,By Android Device Monitor
當我們的程序啟動之后,我們首先啟動Android Device Monitor,按照 選擇應用進程->Start Tracking->點擊登陸按鈕->Get Allocations->Stop Tracking的步驟操作,會得到如下一個窗口。
- 列名解釋
列名 | 解釋 |
---|---|
Alloc Order | 分配序列 |
Allocation Size | 分配的大小 |
Allocated Class | 被分配的對象 |
Thread Id | 線程id號 |
Allocated in | 在哪個類分配的 |
第二個Allocated in | 在哪個方法分配的 |
我們分析一下對象User是如何分配的,在Filter中輸入User的全類名tool.test.memory.memoryleak.domain.User可以只看User的內存分配軌跡情況,如下所示。
上圖中可以看到,在第1337次內存分配中,分配的是User對象,占用內存32字節,處理線程Id為1,在tool.test.memory.memoryleak.HomeActivity中的createObject方法中分配的。下面這段log可以知道User這個對象時如何被創建出來的。
at tool.test.memory.memoryleak.HomeActivity.createObject(HomeActivity.java:24)
at tool.test.memory.memoryleak.HomeActivity.onCreate(HomeActivity.java:18)
at android.app.Activity.performCreate(Activity.java:5975)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1111)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2417)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2526)
at android.app.ActivityThread.access$800(ActivityThread.java:169)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1421)
at android.os.Handler.dispatchMessage(Handler.java:111)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5549)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)
Zygote, 意思是“受精卵”,系統中幾乎所有的應用進程都是由Zygote進程孵化出來的,/system/bin/app_process 啟動時創建了一個AppRuntime對象,通過AppRuntime對象的start方法,通過JNI調用創建了一個虛擬機實例,然后運行com.android.internal.os.ZygoteInit類的靜態main方法,ActivityManagerService由SystemServer創建,所以ActivityManagerService駐留于SystemServer進程中,SystemServer向Zygote發送了消息(Socket),Zygote就fork創建子進程(子進程出來作為這個即將要啟動的應用程序的進程),子進程調用android.app.ActivityThread的main函數,之后就是一個Activity的啟動流程,在Activity創建之后,就走到了Activity的createObject。
參考:Android系統進程Zygote啟動過程的源代碼分析
二、啟動方式二,By Android Monitor
追蹤內存分配也可以由Android Monitor啟動,如圖所示,我們監控了19.5s到34.8s這段時間內存的變化。
在內存圖中點擊途中箭頭的部分,啟動追蹤,再次點擊就是停止追蹤,隨后自動生成一個alloc結尾的文件,這個文件就記錄了這次追蹤到的所有數據,然后會在右上角打開一個窗口。展示和第一種方式有點區別,各有所長,他有兩種展現方式。
- Group by Method:用方法來分類我們的內存分配,默認會以Group by Method來組織
- Group by Allocator:用內存分配器來分類我們的內存分配
我們用 Group by Allocator的方式來查看一下。
可以看到我們自己包中,每一個類的內存分配次數和分配的大小。如果我們想看內存分配的實際在源碼中發生的地方,可以選擇需要跳轉的對象,點擊該按鈕就能發現我們的源碼。
三、統計圖
如果你愿意一層一層一層的剝開我的心,你會發現 你會訝異,你是我 最壓抑,最深處的秘密
雖然比較炫酷,但是個人覺得用途不是很大,沒有第一種方式直觀。
三、全局查看內存使用情況
一條簡單的命令就OK
adb shell dumpsys meminfo [package-name]
連命令都不想敲的人也可以,進入Android Monitor-->System information-->Memory Usage一路點過來,Android Studio就會生成一個全局的內存查看文件。
列名 | 解釋 |
---|---|
Naitve Heap Size | 從mallinfo usmblks獲得,代表最大總共分配空間 |
Native Heap Alloc | 從mallinfo uorblks獲得,總共分配空間 |
Native Heap Free | 從mallinfo fordblks獲得,代表總共剩余空間 |
還有一欄時Objects,這里可以看到內存中Views,和Activity的數量,當前View的數量是32,Activity 的數量是2,當我們的應用完全退出時,View的數量和Activity的數量如下:
所以這個也可以作為我們判斷一個應用有沒有發生內存泄露的一個重要手段。OK,Android性能優化第4篇到此結束。
Please accept mybest wishes for your happiness and success !