什么是内存泄漏?


  简单理解:没有被GC ROOT直接或者间接引用的对象的内存回收掉


性能优化就得考虑使用工具进行检测,Android关于内存工具很多,要能够定位剖析问题。但是会有写场景不会覆盖到,只能发现问题的能力工具。整合下基本使用到的工具。


top/procrank
STRICTMODE(楼主没有使用过)
MAT、Finder
meminfo
LeakCanary
LeakInspector
APT(腾讯开源:https://code.csdn.net/Tencent/apt/tree/master)
Allocation Tracker
Chrome Devtool 
Systrace
Android Architecture Components

 

 


top/procrank

对于此工具来讲,需要知道几个名词含义:


VSS    Virtual Set Size       虚集合大小 
RSS    Resident Set Size      常驻集合大小 
PSS    Proportional Set Size  比例集合大小
USS    Unique Set Size        独占集合大小 

 

  RSS 与 PSS 差不多,包含进程共享内存,RSS没把共享内存大小平分到使用共享的进程上,所以所有进程的RSS相加会超过物理内存。 
  VSS是虚拟地址,它上线与进程的可访问地址有关,和当前进程的内存关系不大。 
  PSS包含进程间共享的内存,而USS不包括,进程USS相加小于物理内存大小的原因。对于PSS而言,如果A进程和B进程同时共享同一个SO库,那就平分到了A和B上,但启动A进程,B没有启动,则B的PSS曲线图会有较大的阶梯状下滑。对于USS而言,它的坑在Dalvik申请内存会有GC延时及其策略,会影响曲线波动。
  
  
  VSS >= RSS >= PSS >= USS

 

 


meminfo

 


  使用dumpsys meminfo 命令 
  用法: dumpsys meminfo options:[-a][–oom][process] 
  -h帮助信息 
  -a打印所有进程的内存信息,以及当前设备的内存概况 
  –oom 按照OOM Adj值进行排序。 
  [Process]进程名,也可以是id 
  比如:dumpsys meminfo | grep -i phone,查 phone相关进程。 
  watch -n 5 dumpsys meminfo com.android.phone 每隔5秒刷新一次

 

 


Procsatats

 


  要提到一个公式:内存负载 = PSS X 运行时长 
  内存负载在Android4.4上提出来(App在手机设备上显示一样),分为:前台,后台,缓冲负载。 
  前台,用户当前使用的,用户不关注的,内存负载不应该默认显示。 
  后台,是app行为,系统无权kill掉并回收,并非用户当前所使用,被默认展示。 
  缓冲,可以回收,内存负载不应该默认展示,没有被杀死是软件的恢复能力,是系统的责任。

 

 


DDMS

 

 

(Dalvik Debug Monitor Server)

 


  各种调试信息集合,有时延,内存,线程,cpu等各种信息展示,经常使用Heap、Allocation Tracker 和 Dump Hprof file(内存快照)。

 

Update Heap获取GC信息,当前已分配内存,当前运行的对象,所剩内存,动态虚拟机heapSize,及其分布柱状图
Allocation Tracker , 展示了500条的内存分配,相关的线程堆栈信息。申请的内存大,GC就多,GC会挂起全部线程,会导致卡顿现象。
Dump Hprof file,选中进程,进行内存快照,Android Studio上有此功能。

 


MAT


  全称:Memory Analyzer(内存分析),需要抓取Hprof文件,最简单使用ddms抓取,其次就是命令


抓取hprof命令如下(在adb shell模式下): 


am dumpheap pid outfilePath (文件名必须为hprof)

 


 

操作:(DDMS抓取的可以直接忽略转格式问题) 
1. adb shell am dumpheap  com.android.phone   /data/local/tmp/test.hprof 
2. adb pull /data/local/tmp/test.hprof c:\test.hprof 
3. hprof-conv c:\test.hprof c:\testConv.hprof

 

Finder


Activity  获取dump的所有Activity对象 
Top Classes  对象数量或对象大小为维度来获取对象降序列表
Compare  对比两个Hprof文件内容的差别
Bitmap 获取dump的所有bitmap对象
Same Bytes 查询dump 中以byte[]类型出现并且内容重复的对象 
Singleton 查询dump中的单例


能够准确定位80%的泄漏问题 

 

LeakCanary


  – 在onDestory 时检查弱引用,使用ReferenceQueue,白名单需要写死在AndroidExcludedRefs.java中。每次得重新编译,区分系统版本。
  
  – 能识别系统泄漏,能够给出一个分析。
  
  – 需要人工修复解决内存泄漏问题 
  
  – 使用开源组件HAHA 分析(参考简书),返回一条GC链。

 


LeakInspector


  – 在onDestory 时检查弱引用,使用WeakReference,提供回调方法,能增加自定义的LOG,TRACE,DUMPSYS信息,需要在白名单以XML配置的形式存放到服务器上,不区分系统版本。
  
  –  可以进行预处理,在ondestroy里,通过反射自动修复系统泄漏。
  
  – 可以对对整个Activity的View遍历一遍,把图片所占用的内存数据释放掉,能够减少对内存的影响
  
  – 采集dump后,自动通过Magnifier上传dump文件,调用MAT命令进行分析,返回GC链。
  
  – 可以跟自动化测试无缝结合,自动化脚本执行过程中发现内存泄漏,收集dump发送到服务器上,分析,生成JSON结果。

 


JHat


  Oracle公司开发的多人协作Hprof分析工具
  
  使用命令:jhat test.prof
  
  解析prof文件,开启httpSrv服务,维护解析后的数据,默认端口7000,直接访问查询。

 


libc_malloc_deBug_leak.so库


  Android系统底层调用libc.so申请内存,而libc_malloc_deBug_leak库就是监视libc.so内部接口的调试库
  
  Native Heap 就是类内存申请部分,NDK编译出来的so文件放到系统的 /data 目录中,size字段的值就是内存大小,每一个都拥有一个申请的调用栈,根据栈后的method字段值能够知道该方法的内存偏移,使用addr2line.exe转化方法名称,注需要编译选项中加入“-Wl,-Map=xxx,map -g”

 


APT


  腾讯开源的测试工具,是DDMS的插件,能够实时监控多个app的cpu及其内存情况,以图表形式展示出来
  
  参考官方

 


GC Log


  Logcat输出的log日志,分为Dalvik Log和ART Log两种

 

Dalvik GC Log


GC 产生原因:


GC_EXPLICIT : 通过Runtime.gc()与VMRuntime.gc(),SIGUSR1触发产生GC,支持并发GC,列表滑动,动画播放,不要有这种Log,高CPU低响应时延不要人工触发GC。
GC_FOR_[M]ALLOC : 没有空闲内存空间给要分配的内存,不是并发GC,会有卡顿,尽量避免。
GC_FOR_CONCURRENT : 当超过堆占用阀值时会触发,局部的并发GC 。
GC_BEFORE_OOM : 在出发OOM前触发的GC,不能局部并发,耗时长,会卡顿。
GC_HPROF_DUMP_HEAP : 在dump内存前触发GC,不能局部并发,耗时长,会卡顿。

 

  查看工具:Dalvik GC Log 绘制成图表的工具

 

ART GC Log


GC 产生原因:


GC_EXPLICIT : 通过Runtime.gc()与VMRuntime.gc(),SIGUSR1触发产生GC,支持并发GC,列表滑动,动画播放,不要有这种Log,高CPU低响应时延不要人工触发GC。
GC_FOR_[M]ALLOC : 没有空闲内存空间给要分配的内存,不是并发GC,会有卡顿,尽量避免。
GC_FOR_CONCURRENT : 当超过堆占用阀值时会触发,局部的并发GC 。
NativeAlloc : Native内存不足以分配内存时触发。
Background : 后台GC,给后面的内存申请预留空间。


GC 类型:


Full : 跟Dalvik 的Full一样
Partial: 跟Dalvik局部GC一样,没有Zygote Heap策略
Sticky 局部中的局部GC ,上次垃圾回收后新分配的对象。


GC 的三种方式:


mark sweep : 记录全部对象,从GC ROOT中找出直接或间接的对象做标注,利用之前记录的全部对象和标注对象做对比,剩余的便是要回收的。
concurrent mark sweep :  使用mark sweep的并发GC
mark compact : 对所有活动的对象压缩到内存的一侧,另外一侧进行回收。
semispace : 把所有引用的对象从一个空间放到另外一个空间,剩余在旧空间的对象就是要直接GC掉的。

 


Allocation Tracker


  Android Studio 里打开Monitor,选择要查看的进程,选择Allocation Tracker,录制出结果按照Size排序,能够直接通过dump to source跳转到对应代码行。  

 


Chrome Devtool


  需要安装Chrome浏览器,移动端和PC端,PC 端访问Chrome://inspect ,点击调试页面下的inspect,出来开发者工具
  
  官方中文文档

 


Systrace


  Android4.1上引入的性能分析工具,能够输出各个线程的当前函数调用状态,并且可以跟当前CPU的线程运行状态、VSYNC、SurfaceFlinger等系统信息在同一时间轴上进行对比。但不是所有手机机型都能支持。
  
  SurfaceFlinger服务在每个VSYNC信号中断时调用一次,那APP显示非常流畅。
  
  如果VSYNC的上升沿SurfaceFlinger服务没有调用,那会导致丢帧。 
  (1) CPU负载过大,低端机型的单核机型上会有发生。在VSNYC中断信号处,CPU闲暇,没有执行其他进程任务时,那我们需要做进一步分析 
  (2) 应用侧没有完成绘制,应用内部处于繁忙时,查看performTraversals信息,忙于其他业务逻辑没有绘制,那看是否忙于分发响应事件。如果当前窗口视图太多,布局嵌套太深,会导致查找响应输入事件的控件耗时长,没法绘制UI。
  
  对于绘制等问题,Google添加了一些警告; 
  (1) Inefficient View alpha usage(5.1+以上才有)
  
  (2) Expensive rendering with Canvas.saveLayer()
  
  
    Canvas.saveLayer()会打断绘制过程中的渲染管道,替换使用View.LAYER_TYPE_HEARDWARE或者static Bitmaps,会让离屏缓存服用相邻两帧间的数据,避免渲染目标被切换而打断。
  
  
  (3) Path Texture Churn
  
  (4) Expensive Bitmap uploads
  
  
    Bitmaps 在硬件加速下,修改和图像的变化都会上传给GPU,如果像素总量大,会消耗GPU的较大资源,所以建议减少每帧中对图片的修改,出现调用setLayerType为LAYER_TYPE_SOFTWARE之后,此时整个屏幕变成一张图。
  
  
  (5) Inflation during ListView recycling
  
  
    没用ListView复用,造成inflate的单个Item的getView成本比较高
  
  
  (6) Inefficient ListView recycling/rebinding
  
  
    每帧的ListView recycling 耗时较长,那得看下Adapter.getView()绑定数据的时候是否存在问题
  
  
  (7) Expensive Measure/Layout pass
  
  
    Measure / Layout 耗时导致卡顿,动画时,不要触发Layout
  
  
  (8) Long View.draw()
  
  
    Draw 本身耗时比较长,避免在View 或 Drawable 的onDraw里面执行任务频繁自定义操作,特别时申请内存和绘制Bitmap.
  
  
  (9) Blocking Garbage Collection
  
  
    GC导致卡顿,就是GC for Alloc的stop the world,避免在动画的时候生成对象,尽量重用Bitmap能够避免触发GC。
  
  
  (10) Lock contention
  
  
    UI 线程锁,UI线程去使用其他线程持有的锁,检查现有UI线程锁并确认它锁住的时间长短。
  
  
  (11)  Scheduling delay
  
  
    网络I/O、磁盘I/O 等线程资源争抢,导致有一定时间的UI线程实际耗时长,而卡顿,检查后台线程是否都云溪nag在低优先级的线程上(是否比Thread_Priority_background还低)。
  

 


Android Architecture Components


  Android 架构组件
  
  存储数据,管理生命周期,模块化,避免常见错误,减少样板文件
  
  
    Lifecycles
  
  
  每个 Android 开发者都应该面对过生命周期问题,即操作系统启动、停止和销毁 Activity。这意味着开发者需要根据生命周期的不同阶段,有针对性地管理组件状态,比如用于更新用户界面的可观察对象。生命周期管理(Lifecycles)帮助开发者创建 “可感知生命周期的” 组件,让其自己管理自己的生命周期,从而 减少内存泄露 和崩溃的可能性。生命周期库是其他架构组件(如 LiveData)的基础。
  
  
    LiveData     
  
  
  LiveData 是一款基于观察者模式的可感知生命周期的核心组件。一种可观测数据容器,它会在数据变化时通知观测器,以便更新界面。
  
  LiveData 为界面代码 (Observer)的监视对象 (Observable),当 LiveData 所持有的数据改变时,它会通知相应的界面代码进行更新。同时,LiveData 持有界面代码 Lifecycle 的引用,这意味着它会在界面代码(LifecycleOwner)的生命周期处于 started 或 resumed 时作出相应更新,而在 LifecycleOwner 被销毁时停止更新。通过 LiveData,开发者可以方便地构建安全性更高、性能更好的高响应度用户界面。
  
  有两个对应接口,LifecycleOwner和LifecycleObserver; 
  LifecycleOwner是具有生命周期的对象,比如Activity和Fragment. 
  LifecycleObserver观测LifecycleOwner,并在生命周期变化时收到通知。
  
  
    ViewModel     
  
  
  ViewModel 将视图的数据和逻辑从具有生命周期特性的实体(如 Activity 和 Fragment)中剥离开来。直到关联的 Activity 或 Fragment 完全销毁时,ViewModel 才会随之消失,也就是说,即使在旋转屏幕导致 Fragment 被重新创建等事件中,视图数据依旧会被保留。ViewModels 不仅消除了常见的生命周期问题,而且可以帮助构建更为模块化、更方便测试的用户界面。
  
  
    Room
  
  
  一款简单好用的SQL对象映射库。它和 SQLite 有一样强大的功能,但是节省了很多重复编码的麻烦事儿。它的一些功能,如编译时的数据查询验证、内置迁移支持等,更简单地构建健壮的持久层。而且 Room 可以和 LiveData 集成在一起,提供可观测数据库并感知生命周期的对象。Room 集简洁、强大和可靠性为一身,在管理本地储存上表现卓越。
  
  
    PagedList
  
  
  解决用 RecyclerView 处理大数据集的困难。
  
  App 架构指南 
  Android 架构组件官网

 

 


参考博客地址:

开源项目之LeakCanary源码分析: http://www.jianshu.com/p/5032c52c6b0a

查找并修复Android中的内存泄露—OutOfMemoryError: 
https://yq.aliyun.com/articles/40294

内存分析工具 MAT 的使用 :  
http://blog.csdn.net/aaa2832/article/details/19419679

Android 查看内存使用工具 (procstats): 
http://blog.csdn.net/vshuang/article/details/51755756

Android进程内存统计工具procstats: 
https://wenku.baidu.com/view/c8d49549b90d6c85ed3ac63b.html
--------------------- 
作者:jink_l 
来源:CSDN 
原文:https://blog.csdn.net/superloveboy/article/details/78536750 
版权声明:本文为博主原创文章,转载请附上博文链接!

更多相关文章

  1. Android之ContentProvider源码解析
  2. Android(安卓)Bluetooth
  3. Android(安卓)缓存管理和LRU 算法
  4. Android(安卓)安全攻防
  5. J2ME游戏只移植到Android平台(一)
  6. Handler&Looper
  7. Android系统的上下文对象Context
  8. Android应用程序开发(第三版)-课后习题解答
  9. [Android] [Java] 分享 Process 执行命令行封装类

随机推荐

  1. Android设置权限问题
  2. Android有两种方法检测USB设备插入
  3. Android学习笔记1
  4. android实现点击按钮控制图片切换
  5. 我的第一个Android 多媒体的Demo
  6. Android请求获取Java后端数据,登录界面例
  7. Android(安卓)Gesture手势操作(手势翻页
  8. 百度地图开发Marker|Polyline隐藏或显示
  9. 从Android读取Unity assets下的图片并保
  10. (详细代码,文末Demo下载)android简单修改密