2020-03-25-Android的内存泄漏

2020-03-27  本文已影响0人  耿望

常见的几种内存泄漏场景

1.静态实例
我们使用静态实例的时候需要警惕它的生命周期,因为它跟应用程序的生命周期一样长,比如在Activity中使用静态实例,就算Activity已经被回收,静态实例还会存在。

public class SecondActivity extends AppCompatActivity {

    private static Object sInner = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        MyParcel parcel = getIntent().getParcelableExtra("parcel");
        Log.d(TAG, "parcel " + parcel);
        sInner = new InnerClass();
        InnerClass inner = new InnerClass();
    }

    class InnerClass {
        String name;
        int value;
    }
}

2.异步任务
在异步线程中执行耗时操作,也可能造成内存泄漏,比如下面的例子,在AsyncTask中写一个while循环,就算Activity已经销毁,这里还是会持有一个Activity的引用。

public class SecondActivity extends AppCompatActivity {

    private AsyncTask asyncTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        MyParcel parcel = getIntent().getParcelableExtra("parcel");
        Log.d(TAG, "parcel " + parcel);
        asyncTask = new AsyncTask() {
            @Override
            protected Object doInBackground(Object[] objects) {
                while (true);
            }
        };
        asyncTask.execute();
    }
}

内存泄漏的分析工具

1. Profile
这是Android Studio自带的工具,不仅是内存,同时可以监控CPU,网络等资源。调试定位问题确实是方便快捷,但是有个问题,经常会连接不上,总是要把adb重启一下或者是重启android studio。
在windows平台上,可以通过tasklist命令查看所有进程,tskill [PID] 杀死adb进程。
通过netstat命令查看端口和连接情况。
下图可以看到,profile分成5个区域:
第一行是event事件,包括activity的启动销毁等;
第二行是CPU资源;
第三行是内存资源;
第四行是网络资源;
第五行是电量使用情况。

3.PNG
我们看下内存资源,profile将不同内存区域标识出来,stack是虚拟机栈内存,Java是堆内存,code应该是方法区,graphics是图形缓存区,native是c/c++分配的内存,allocated是分配的对象数量,others是其他。
4.PNG
以上面第一个内存泄漏的例子为例,我们看下怎么定位内存泄漏问题,选中一段区域之后,会自动显示这段时间分配的对象信息,直接查找InnerClass类,右边是它的所有实例,其他普通实例都能够在onDestroy之后被回收,只有那个静态实例,也就是第二个instance,一直没有被回收。
1.PNG
可以看到,直到整个应用退出了,这个实例依然存在。
2.PNG
更精确的信息也可以请看dumphead,图里有个垃圾桶按钮和一个下载按钮,分别代表强制gc和抓取dumpheap。
5.PNG
2. Memory Analyzer(MAT)
实际上也可以通过简单的adb命令先定位问题,比如meminfo
Applications Memory Usage (in Kilobytes):
Uptime: 32331378 Realtime: 175875568

** MEMINFO in pid 29973 [com.one.powerexception] **
                   Pss  Private  Private  SwapPss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap     7871     7788        0        4    22528    12161    10366
  Dalvik Heap     1387     1324        0        0     2351     1764      587
 Dalvik Other      857      852        0        0                           
        Stack       60       60        0        0                           
       Ashmem        2        0        0        0                           
      Gfx dev      788      788        0        0                           
    Other dev       20        0       20        0                           
     .so mmap     2226       76      128        0                           
    .jar mmap     1051        0        8        0                           
    .apk mmap      241        0        0        0                           
    .ttf mmap       97        0        0        0                           
    .dex mmap     2200     2200        0        0                           
    .oat mmap       69        0        0        0                           
    .art mmap     6077     5784       64        0                           
   Other mmap      311      132        0        0                           
    GL mtrack     5880     5880        0        0                           
      Unknown      828      808        0        0                           
        TOTAL    29969    25692      220        4    24879    13925    10953
 
 App Summary
                       Pss(KB)
                        ------
           Java Heap:     7172
         Native Heap:     7788
                Code:     2412
               Stack:       60
            Graphics:     6668
       Private Other:     1812
              System:     4057
 
               TOTAL:    29969       TOTAL SWAP PSS:        4
 
 Objects
               Views:       16         ViewRootImpl:        0
         AppContexts:        6           Activities:        1
              Assets:       15        AssetManagers:        0
       Local Binders:       14        Proxy Binders:       31
       Parcel memory:        4         Parcel count:       18
    Death Recipients:        1      OpenSSL Sockets:        0
            WebViews:        0
 
 SQL
         MEMORY_USED:        0
  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0

我们可以通过adb的dumpheap命令抓取prof信息,这个命令会在/data/local/tmp/目录下生成一份Prof文件,然后通过android studio自带的hprof-conv工具转换成hprof,在MAT工具中分析。

adb shell dumpsys meminfo com.one.powerexception
adb shell am dumpheap -g com.one.powerexception
hprof-conv heapdump.prof hf.hprof
2.PNG
3.PNG

主要是几个区域:

  1. Histogram:对象的个数和大小
  2. Dominator Tree:最大的对象以及其依赖存活的Object
  3. Shallow size:对象本身占用内存的大小,不包含其引用的对象
  4. Retained Heap:如果一个对象被释放掉,那会因为该对象的释放而减少引用,进而被释放的所有的对象(包括被递归释放的)所占用的heap大小

参考:

使用 Memory Profiler 查看 Java 堆和内存分配
Android Profile Tools 入门
关于使用Eclipse Memory Analyzer的10点小技巧
Android Studio 的dump java heap以及mat调试

上一篇下一篇

猜你喜欢

热点阅读