美文网首页
2020-03-25-Android的内存泄漏

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

作者: 耿望 | 来源:发表于2020-03-27 16:23 被阅读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调试

    相关文章

      网友评论

          本文标题:2020-03-25-Android的内存泄漏

          本文链接:https://www.haomeiwen.com/subject/wajtuhtx.html