最易懂内存泄漏定位分析 - profiler的应用


内存泄漏:内存不在GC掌控之内了。当一个对象已经不需要再使用了,本该被回收时,而有另外一个正在使用的对象持有它的引用从而就导致,对象不能被回收。这种导致了本该被回收的对象不能被回收而停留在堆内存中,就产生了内存泄漏

四中引用:

StrongReference强引用: 
回收时机:从不回收 使用:对象的一般保存 生命周期:JVM停止的时候才会终止
SoftReference软引用 
回收时机:当内存不足的时候;使用:SoftReference结合- ReferenceQueue构造有效期短;生命周期:内存不足时终止
WeakReference,弱引用 
回收时机:在垃圾回收的时候;使用:同软引用; 生命周期:GC后终止
PhatomReference 虚引用 
回收时机:在垃圾回收的时候;使用:合ReferenceQueue来跟踪对象呗垃圾回收期回收的活动; 生命周期:GC后终止
开发时,为了防止内存溢出,处理一些比较占用内存大并且生命周期长的对象的时候,可以尽量使用软引用和弱引用。 
软引用比LRU算法更加任性,回收量是比较大的,你无法控制回收哪些对象。

android profiler 查找内存泄漏

代码:

protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_memory_link);

    //懒汉式单例
    TestUtil instance = TestUtil.getInstance(this);
}
class TestUtil {
    private static TestUtil instance;
    private final Context mContext;

    public TestUtil(Context context) {
        this.mContext = context;
    }

    public static TestUtil getInstance(Context context) {
        if (instance == null) {
            instance = new TestUtil(context);
        }
        return instance;
    }
}

上面代码是非常常见的懒汉式单例模式,安装apk运行后,在androidstudio中View-ToolWindwos-Profiler,打开内存分析工具,选择自己的应用。

最易懂内存泄漏定位分析 - profiler的应用_第1张图片

 

最易懂内存泄漏定位分析 - profiler的应用_第2张图片

此时可以看到CPU、MEMORY、ENERGY等的实时信息,我们分析内存相关,点击MEMORY,然后手机切换为横屏再切换为竖屏。

最易懂内存泄漏定位分析 - profiler的应用_第3张图片

然后步骤1,点击dump按钮将hprof文件dump下来

最易懂内存泄漏定位分析 - profiler的应用_第4张图片

在执行1、2步操作后生成dump信息,选中我们需要分析的app head 按ctrl + f 搜索自己应用的包名,可以看到应用内存在的对象,以及对象的个数,从第4、5步看出,app中有三个MemoryLinkActivity的对象,对象的depth值为0是可以被GC回收的,否则就不能回收,从第6步可以看出,当前对象被TestUtil持有,无法回收出现内存泄漏,这个对象就是最开始启动界面时,activity传给TestUtil的,一直被静态的TestUtil持有,无法释放,再看下一个对象

最易懂内存泄漏定位分析 - profiler的应用_第5张图片

此对象没有被我们代码中的类持有,而是被ActivityThread持有,这个就是我们当前显示的界面对象,当前显示界面对象不会被回收,再看最后一个

最易懂内存泄漏定位分析 - profiler的应用_第6张图片

这个对象既没有被我们代码中的类持有,又没有被ActivityThread持有,这个是横屏后的MemoryLinkActivity,此时正在等待被回收,它的depth值为0,是可以被回收的,下面验证下上文分析:

最易懂内存泄漏定位分析 - profiler的应用_第7张图片

点击第1步的GC回收按钮,执行第2步再次dump出数据,再次观察dump数据,MemoryLinkActivity横屏的对象已经被GC掉,而被TestUtil持有的对象无法GC,存在泄漏,与之前的分析一致。

同样道理,我们将获取单例的代码注释掉,看看空activity的情况

// TestUtil instance = TestUtil.getInstance(this);

最易懂内存泄漏定位分析 - profiler的应用_第8张图片

可以看到,横竖屏之后,有三个对象,两个可以回收,当前显示的不可以回收,GC后再观察:

最易懂内存泄漏定位分析 - profiler的应用_第9张图片

除了当前对象,其余对象全部回收,完全不存在内存泄漏的问题。

至此,使用androidstudio profiler的基本操作完结,内存泄漏,gc就无法回收,一部分的内存在应用的这次生命周期中就不再可用,这样的泄漏多了就造成了OOM。所以,定位的时候,找到自己的包名,对比对象数据异常的类,看看哪些对象是GC之后还是没有释放的,再看看这些对象中哪些是合理的(如当前显示对象),其余的不合理的未释放的对象,就是泄漏的。

 

android profiler 其他一些字段含义:

您可以查看以下信息:

  • Heap Count:堆中的实例数。
  • Shallow Size:此堆中所有实例的总大小(以字节为单位)。
  • Retained Size:为此类的所有实例而保留的内存总大小(以字节为单位)。

在类列表顶部,您可以使用左侧下拉列表在以下堆转储之间进行切换:

  • Default heap:系统未指定堆时。
  • App heap:您的应用在其中分配内存的主堆。
  • Image heap:系统启动映像,包含启动期间预加载的类。 此处的分配保证绝不会移动或消失。
  • Zygote heap:写时复制堆,其中的应用进程是从 Android 系统中派生的。

默认情况下,此堆中的对象列表按类名称排列。 您可以使用其他下拉列表在以下排列方式之间进行切换:

  • Arrange by class:基于类名称对所有分配进行分组。
  • Arrange by package:基于软件包名称对所有分配进行分组。
  • Arrange by callstack:将所有分配分组到其对应的调用堆栈。 此选项仅在记录分配期间捕获堆转储时才有效。 即使如此,堆中的对象也很可能是在您开始记录之前分配的,因此这些分配会首先显示,且只按类名称列出。

默认情况下,此列表按 Retained Size 列排序。 您可以点击任意列标题以更改列表的排序方式。

Instance View 中,每个实例都包含以下信息:

  • Depth:从任意 GC 根到所选实例的最短 hop 数。
  • Shallow Size:此实例的大小。
  • Retained Size:此实例支配的内存大小(根据 dominator 树)。

你可能感兴趣的:(工具,内存泄漏,最易懂,profiler,工具,定位)