众所周知android应用是基于JAVA语言开发的,JAVA有自己的垃圾回收机制,因此我们不用再释放内存、资源回收方面花费太多的精力,但是JAVA的GC(Garbage Collection)机制是自动进行的,因此在APP开发当中难免会遇到内存泄露,而android分配给每个应用的内存大小是有限制的因此大量的内存泄露积少成多会造成内存溢出(out of memory).所以我们应当重视内存优化问题.接下来我将通过Studio创建一个简单的单例模式内存泄露的例子,使用MAT(Eclipse MemoryAnalyzer)来进行分析.
栈
存放基本数据类型以及对象的引用地址(指向堆里具体的对象),不负责存储对象
堆
为对象开辟内存空间,保存对象,GC负责管理这里的内存回收
什么是内存泄露
内存泄露表示当前对象被大于其本身生命周期的其他对象持有引用,而GC只会去回收堆内存中没有被引用的的对象,这样导致内存中持有这些实例不能被回收,然后慢慢积累越来越多造成卡顿甚至内存溢出
MAT下载
MAT有对应的eclipse插件,但是大部分开发是在studio下进行的,因此附上MAT应用的下载地址
MAT的下载地址
创建内容泄露实例
创建主Activity
public class MainMATActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mat_main);
findViewById(R.id.btn_go).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainMATActivity.this, LeakMemoryActivity.class);
startActivity(intent);
}
});
创建单例模式的LeakManager,在构造函数里引用Activity的Context
public class LeakManager {
private static final String TAG=LeakManager.class.getSimpleName();
public Context context;
private static LeakManager leakEntity=null;
public static LeakManager getInstance(Context context) {
if (leakEntity == null) {
leakEntity = new LeakManager(context);
}
return leakEntity;
}
private LeakManager(Context context) {
this.context = context;
}
public void doTask(){
Log.e(TAG,"哈哈,吃的别想让我吐出来!");
}
}
创建内存泄露Activity
public class LeakMemoryActivity extends Activity {
private static final String TAG = LeakMemoryActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView textView = new TextView(this);
textView.setGravity(Gravity.CENTER);
textView.setText("Leark Memory Activity");
setContentView(textView);
LeakManager.getInstance(this).doTask();
}
}
在第三步中我们创建了LeakMemoryActivity并完成LeakManager单例模式下的初始化,也就是说LeakManger已经保持了LeakMemory的Context引用.接下来启动APP.
生成hprof分析文件
打开Android Device Monitor、选中需要监听的应用程序、点击update heap
这时候右边显示一个Heap界面如下,如果没有点击Window->Show View->Android->Heap,然后点击Cause GC即可出发垃圾回收。HeapSize表示APP堆内存大小,Allocated表示已经分配的内存大小
点击MainMATActivity按钮跳转到LeakMemoryActivity,然后返回然后在跳转、返回,随后点击Dump HPROF file生成hprof文件,如果项目较大可能会慢一些,然后保存到指定位置
这个时候生成的一般是包名.hprof文件,这个文件目前还不能被MAT打开,需要SDK的命令转换一下
hprof-conv /Users/.../com.ymy.app.hprof(源文件路径) /Desktop/hprof/out.hprof(转换后的路径)
使用MAT分析内存使用情况
打开MAT
选择cancle,点击 Open a Heap Dump,打开刚才转换后的out.hprof文件
之后展示的页面,下载的Actions中有Histogram(列出内存中对象的名称数量大小)、Dominator Tree(将内存中的对象按大小进行排序)
先介绍下几个关键词表示的意思
Objects
当前对象的数量
Shallow Heap
表示当前对象抛开引用关系自己所占的内存大小
Retained Heap
表示这个对象以及它所持有的其它引用(包括直接和间接)所占的总内存,在Histogram下没有具体值