0


安卓性能优化之内存优化

Java对象生命周期:

  1. 创建:为对象分配内存空间,构造对象
  2. 应用:此时 对象至少被一个强引用持有
  3. 不可见:未被任何强引用持有,进行可达性分析
  4. 不可达:可达性分析为不可达,进入下一阶段
  5. 收集:当垃圾回收器发现该对象已经处于“不可达阶段”并且垃圾回收器已经对该对象的内存空间重新分配做好准备时,则对象进入了“收集阶段”。如果该对象已经重写了finalize()方法,则会去执行该方法的终端操作。
  6. 终结:当对象执行完finalize()方法后仍然处于不可达状态时(可达性分析垃圾回收算法被回收前,会有两次标记过程,判断是否执行l finalize()方法,执行完之后判断是否GC ROOT可达,如果仍不可达,则准备回收),则该对象进入终结阶段。在该阶段是等待垃圾回收器对该对象空间进行回收。
  7. 对象空间进行重新分配

对象的内存布局:

请添加图片描述

Android内存回收机制:

  1. 对象创建后在Eden区
  2. 执行GC后,如果对象仍然存活,则复制到S0区
  3. 当S0区满时,该区域存活对象将复制到S1区,然后S0区清空,接下来S0和S1角色互换.
  4. 当第3步达到一定次数(系统版本不同会有差异)后,存活对象将对复制到Old Generation
  5. 当这个对象在Old Greneration停留的时间达到一定程度时,它会被移动到Old Generation,最后积累一定时间再移动到Permanent Generation区域

年轻代使用mimor GC速度快,老年代使用full GC速度就会慢很多。

Dalvik虚拟机内存分配:

  • Linear Alloc:匿名共享内存
  • Zygote Space:Zygote相关的一些信息
  • Alloc Space:每个进程 独占

ART:

Non Moving Space

Zygote Space

Alloc Space

Image Space:预加载的类信息

Large Obj Space:分配大对象 如bitmap

可达性分析算法GCoot:

请添加图片描述

Java的四种引用:

  • 强引用
  • 软引用:GC扫描到不一定被回收,只有内存不足时才会被回收
  • 弱引用:被GC扫描到就会被回收
  • 虚引用:没有引用

垃圾回收算法:

标记清除法:

特点:

位置不连续,产生碎片,效率略低,两次扫描

多次扫描后会产生大量内存碎片

复制算法:

特点:

实现简单,运行高效,没有内存碎片,利用率只有一半

假设内存又4M,使用的只有2M

标记整理算法:

特点:

没有内存碎片,效率偏低,两遍扫描,指针需要调整

扫描标记可回收后,整理存活对象和可回收对象,分区

分代收集算法:

综合运用

新生区对象存活低使用复制算法,老年区对象存活久,清除频率低,使用标记算法

App内存组成以及限制

Android给每个app分配一个VM,让app运行在dalvik上,这样即使app崩溃也不会影响到系统。系统给VM分配了一定的内存大小,app可以申请使用的内存大小不能超过此硬件逻辑限制,就算物理内存富余,如果应用超过VM最大内存,就会出现内存溢出crash。
由程序控制操作的内存空间在heap上,分java heapsize 和native heapsize。

  • java申请的内存在vm heap上,所以如果java申请的内存大小超过vm的逻辑内存限制,就会出现内存溢出的异常。
  • native层内存申请不受其限制,native层受native process对内存大小的限制。

查看App内存限制

adb shell

cat /system/build.prop

通过代码获取

ActivityManager activityManager =(ActivityManager)getBaseContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
activityManager.getMemoryClass();

ams为什么能获取:因为 ams.setsystemprocess中的meminfobinder调用底层内存信息

app:内存 大小 每个厂商机型给初始分配内存不同 源码中有两个地方可以修改

1./frameworks/base/core/jni/AndroidRuntime.cpp

    parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
    parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m"); //修改这里
  1. 安卓10以下/system/core/init/init.cpp

OOM解决问题 :主动获取了解当前app的内存使用情况

低内存杀进程机制

请添加图片描述

OOM Killer

oom_adj

app运行时,点击home app挂到后台 不会立马被系统杀掉,开多应用挂后台,安卓系统给应用分级

请添加图片描述

数字越大越容易被系统杀掉,粗粒度

app: 前台可见 oom_adj 0,后台2

oom_score_adj [-1000,1000] 更细粒度杀进程

adb shell下使用 cat /proc/进程号/oom_adj即可查询该应用的oom_adj值

若两个应用a 和b oom_adj值都是11 则谁占用内存多杀谁

所以要尽量降低应用进入后台的内存

内存三大问题

1.内存抖动

内存波动图呈锯齿状,GC导致卡顿

在AS中的Profiler中使用查看波动图,内存抖动会频繁GC,如自定义view中的ondraw()中频繁创建销毁画笔路径等,最后会导致内存千疮百孔

2.内存泄漏

在当前应用周期内不再使用的对象被GC Roots引用,导致不能回收,使实际可使用内存变小

产生泄漏之后不会立马导致应用崩溃,1个地方存在泄漏,程序跑久了之后,内存泄漏会一直积攒着,达到OOM级别,会导致应用低内存,会导致发热,耗电更严重的导致内存溢出

注:OOM不是只代表Java堆内存溢出。还因为无足够连续内存空间:FD(文件句柄,数字)数量超出限制;线程数量超出限制;虚拟内存不足;

3.内存溢出

即OOM,OOM时会导致程序异常。Android设备出厂后,Java虚拟机对单个应用的最大分配内存就确定下来了,超出这个值就会OOM

常见分析内存问题的命令

常用内存调优分析命令:

  1. dumpsys meminfo

内存指标概念:
Item全称含义等价USSUnique Set Size物理内存进程独占的内存PSSProportional Set Size物理内存PSS=USS+按比例包含共享库RSSResident Set Size物理内存RSS=USS+包含共享库VSSVirtual Set Size虚拟内存VSS=RSS+未分配实例物理内存
总结:VSS>=RSS>=PSS>=USS,但/dev/kgsl-3d0部分必须考虑VSS 看的时候主要看PSS

请添加图片描述

dumpsys meminfo --package + 包名可以查看具体应用的内存情况

  1. procrank
  2. cat /proc/meminfo
  3. free
  4. showmap
  5. vmstat
  6. top -n 1

总结:

  • dumpsys meminfo适用场景:查看进程的oom_adj,或者dalvik/native等区域内存情况,或者某个进程或apk的内存情况,功能非常强大
  • procrank:查看进程的VSS/RSS/PSS/USS各个内存指标
  • cat /proc/meminfo 查看系统的详尽内存信息,包含内核情况
  • free适用场景:只查看系统的可用内存
  • showmap 查看进程的虚拟地址控件的内存分配情况
  • vmstat 周期性地打印出进程运行队列,系统切换 ,CPU时间占比等情况

MAT性能分析工具:MemoryAnalyzer Tools

  • incoming references

被持有

  • outgoing references

持有

hprof-conv xxx.hprof 转一下即可用MAT打开内存快照

  • Shallow Heap 浅堆

单独自己的占用大小

  • Retained Heap 深堆

总计引用占用大小


本文转载自: https://blog.csdn.net/liuwushuang233/article/details/128774677
版权归原作者 刘知意 所有, 如有侵权,请联系我们删除。

“安卓性能优化之内存优化”的评论:

还没有评论