版权声明:本文为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 !