咱们先创立一个内存走漏的比如
首先,创立一个简略Android Java工程,里边有MainActivity和MainActivity2,其间MainActivity2用来模仿Handler的内存和单例内存走漏比如
MainActivity 跳转到MainActivity2
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.bt_go).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getApplication(),MainActivity2.class);
intent.putExtra("hhh","hhhh");
startActivity(intent);
}
});
}
}
MainActivity2模仿了handler和单例持有上下文的内存走漏
public class MainActivity2 extends AppCompatActivity {
//界说Handler目标
private Handler handler = new Handler() {
@Override
//当有音讯发送出来的时分就履行Handler的这个方法
public void handleMessage(Message msg) {
super.handleMessage(msg);
Toast.makeText(MainActivity2.this, "数据返回了!", Toast.LENGTH_LONG).show();
Log.i("MainActivity2", "handleMessage -->" + Thread.currentThread().getName());
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
//创立单例,引用活动上下文会发现内存走漏
TestFactory factory = TestFactory.getInstance(MainActivity2.this);
//handler内存走漏测试
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
processThread();
}
});
}
private void processThread() {
//构建一个下载进度条
Log.i("MainActivity2", "processThread()-->" + Thread.currentThread().getName());
new Thread() {
@Override
public void run() {
Log.i("MainActivity2", "run()-->" + Thread.currentThread().getName());
//在新线程里履行长耗时方法
longTimeMethod();
//履行结束后给handler发送一个空音讯
handler.sendEmptyMessage(0);
}
}.start();
}
//模仿下载文件的长耗时方法
private void longTimeMethod() {
try {
Log.i("MainActivity2", "longTimeMethod-->" + Thread.currentThread().getName());
Thread.sleep(10000); //10秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
单例类
public class TestFactory {
private Context context;
private static volatile TestFactory testFactory;
public TestFactory(Context context) {
this.context = context;
}
public static TestFactory getInstance(Context context) {
if (testFactory == null) {
synchronized (TestFactory.class) {
if (testFactory == null) {
testFactory = new TestFactory(context);
}
}
}
return testFactory;
}
}
启动项目,翻开Profiler,绑定咱们的进程,进入内存剖析视图,具体运用方法能够参考上一章
内存走漏的主动剖析需求运用第一种Captrue heap dump Captrue heap dump
每点击一次Record,都会记载当时App内存情况,生成一个Heap Dump记载,所以app操作之后点击一次Record,内存情况记载会跟上一次有所不同的。 GC按钮图标是一个垃圾桶:
翻开内存监控就能够进行操作了 点击Mainctivity的跳转按钮,跳转到Mainctivity2 , 然后点击履行履行processThread函数的方法,这边能够自己实现,退出HMainctivity2,回到MainActivity。然后回到Android Profile,履行一次GC按钮(模仿GC回收不可达的引用),再点击Record按钮,就会得到一个Heap Dump “记载1”
咱们看到,Leaks 数量是2,说明两种情况都内存走漏了
依照箭头的顺序点击便能够查看到走漏的目标 能够看出由于单例持有了活动上下文导致无法被毁掉 第二个走漏是hander的这儿就不打开剖析了
细心的网友可能会问,除了第一个选项,后边两个做什么的呢? 依据注释说明咱们能够知道主要剖析native和kottlin的内存运用情况,如果用这个查内存走漏需求自己调查数据,不是最优挑选
是不是很简略,你学废了吗?