http://blog.csdn.net/xiaanming/article/details/42396507
基本步骤:
1,准备一个有内存泄漏的代码
2,如何发现内存泄漏
3,生成.hprof
4,打开.hprof 文件开始分析
5,修复代码
Cause GC是手动产生一次GC清理下内存,如果多次GC后,可用部分内存变小,使用部分变多,说明有明显的内存泄漏。
如下图: 其中 Free变少,% Used变大 说明有内存泄漏。
a,在打开.hprof 文件时,在向导页面选 Leak Suspects Report
b,在概述页面可以在全局角度查看内存使用情况
c,进入内存泄漏详细报告页面
注意其中的提示和 Keywords 部分.
其中Suspect 1 有两个 java.lang.Object[] 和 android.content.res.Resources ,本文检测第一个关键字。
d,生成柱状图
e,开始定位一个个可疑泄漏,在第一行 <Regex>中输入第一个关键字 java.lang.Object[]
f,在java.lang.Ojbect[]上 点 Merge Shortest Paths to GC Roots -> exclude all phantom/weak/soft etc.references
Merge Shortest Paths to GC Roots 可以查看一个对象到RC Roots是否存在引用链相连接, 在JAVA中是通过可达性(Reachability Analysis)来判断对象是否存活,这个算法的基本思想是通过一系列的称谓"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走得路径称为引用链,当一个对象到GC Roots没有任何引用链相连则该对象被判定为可以被回收的对象,反之不能被回收,我们可以选择 exclude all phantom/weak/soft etc.references(排查虚引用/弱引用/软引用等)因为被虚引用/弱引用/软引用的对象可以直接被GC给回收.
g,可以看到LeakActivity存在GC Roots链,即存在内存泄露问题,可以看到 InnerClassLeaksActivity被 InnerClassHasLeak 的this$0持有。
除了使用Merge Shortest Paths to GC Roots 我们还可以使用
List object - With outgoing References 显示选中对象持有那些对象List object - With incoming References 显示选中对象被那些外部对象所持有Show object by class - With outgoing References 显示选中对象持有哪些对象, 这些对象按类合并在一起排序Show object by class - With incoming References 显示选中对象被哪些外部对象持有, 这些对象按类合并在一起排序我们知道上面的例子代码中我们知道内部类会持有外部类的引用,如果内部类的生命周期过长,会导致外部类内存泄露,那么你会问,我们应该怎么写才不会出现内存泄露的问题呢?既然内部类不行,我们就外部类或者static的内部类,如果我们需要用到外部类里面的一些东西,我们可以将外部类Weak Reference传递进去
1 import android.os.Bundle; 2 import android.support.v7.app.AppCompatActivity; 3 4 import java.lang.ref.WeakReference; 5 import java.util.ArrayList; 6 7 public class InnerClassLeaksActivity extends AppCompatActivity { 8 9 private ArrayList<String> list = new ArrayList<String>(); 10 11 @Override 12 protected void onCreate(Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 setContentView(R.layout.activity_inner_class_leaks); 15 //模拟Activity一些其他的对象 16 for (int i = 0; i < 10000; i++) { 17 list.add("Memory Leak!"); 18 } 19 //开启线程 20 new InnerClassHasLeak().start(); 21 } 22 23 public class InnerClassHasLeak extends Thread{ 24 25 @Override 26 public void run() { 27 super.run(); 28 //模拟耗时操作 29 try { 30 Thread.sleep(10 * 60 * 1000); 31 } catch (InterruptedException e) { 32 e.printStackTrace(); 33 } 34 } 35 } 36 public static class StaticInnerClassNoLeak extends Thread{ 37 private WeakReference<InnerClassLeaksActivity> mLeakActivityRef; 38 39 public StaticInnerClassNoLeak(InnerClassLeaksActivity activity){ 40 mLeakActivityRef = new WeakReference<InnerClassLeaksActivity>(activity); 41 } 42 @Override 43 public void run() { 44 super.run(); 45 //模拟耗时操作 46 try { 47 Thread.sleep(10 * 60 * 1000); 48 } catch (InterruptedException e) { 49 e.printStackTrace(); 50 } 51 //如果需要使用LeakActivity,我们需要添加一个判断 52 InnerClassLeaksActivity activity = mLeakActivityRef.get(); 53 if(activity != null){ 54 //do something 55 } 56 } 57 } 58 }
不光 Thread有这个问题,Handler也有。
转载于:https://www.cnblogs.com/sjjg/p/5351118.html