Android-GC原理探究(深度好文)

所以对于Dalvik虚拟机的手机来说,我们首先要尽量避免掉频繁生成很多临时小变量(比如说:getView,onDraw等函数),另一个又要尽量去避免产生很多长生命周期的大对象。

3、ART内存回收机制

3.1 Java堆

ART运行时内部使用的Java堆的主要组成包括Image Space、Zygote Space、Allocation Space和Large Object Space四个Space,Image Space用来存在一些预加载的类, Zygote Space和Allocation Space与Dalvik虚拟机垃圾收集机制中的Zygote堆和Active堆的作用是一样的,

Large Object Space就是一些离散地址的集合,用来分配一些大对象从而提高了GC的管理效率和整体性能,类似如下图:

在下文的GC Log中,我们也能看到在art的GC Log中包含了LOS的信息,方便我们查看大内存的情况。

3.2 GC的类型

  • kGcCauseForAlloc ,当要分配内存的时候发现内存不够的情况下引起的GC,这种情况下的GC会stop world
  • kGcCauseBackground,当内存达到一定的阀值的时候会去出发GC,这个时候是一个后台gc,不会引起stop world
  • kGcCauseExplicit,显示调用的时候进行的gc,如果art打开了这个选项的情况下,在system.gc的时候会进行gc
  • 其他更多

3.3 对象的分配和GC触发时机

由于Art下内存分配和Dalvik下基本没有任何区别,我直接贴图带过了。

3.4 并发和非并发GC

Art在GC上不像Dalvik仅有一种回收算法,Art在不同的情况下会选择不同的回收算法,比如Alloc内存不够的时候会采用非并发GC,而在Alloc后发现内存达到一定阀值的时候又会触发并发GC。同时在前后台的情况下GC策略也不尽相同,后面我们会一一给大家说明。

  • 非并发GC

步骤1. 调用子类实现的成员函数InitializePhase执行GC初始化阶段。

步骤2. 挂起所有的ART运行时线程。

步骤3. 调用子类实现的成员函数MarkingPhase执行GC标记阶段。

步骤4. 调用子类实现的成员函数ReclaimPhase执行GC回收阶段。

步骤5. 恢复第2步挂起的ART运行时线程。

步骤6. 调用子类实现的成员函数FinishPhase执行GC结束阶段。

  • 并发GC

步骤1. 调用子类实现的成员函数InitializePhase执行GC初始化阶段。

步骤2. 获取用于访问Java堆的锁。

步骤3. 调用子类实现的成员函数MarkingPhase执行GC并行标记阶段。

步骤4. 释放用于访问Java堆的锁。

步骤5. 挂起所有的ART运行时线程。

步骤6. 调用子类实现的成员函数HandleDirtyObjectsPhase处理在GC并行标记阶段被修改的对象。。

步骤7. 恢复第4步挂起的ART运行时线程。

步骤8. 重复第5到第7步,直到所有在GC并行阶段被修改的对象都处理完成。

步骤9. 获取用于访问Java堆的锁。

步骤10. 调用子类实现的成员函数ReclaimPhase执行GC回收阶段。

步骤11. 释放用于访问Java堆的锁。

步骤12. 调用子类实现的成员函数FinishPhase执行GC结束阶段。

所以不论是并发还是非并发,都会引起stopworld的情况出现,并发的情况下单次stopworld的时间会更短,基本区别和。

3.5 Art并发和Dalvik并发GC的差异

首先可以通过如下2张图来对比下

Dalvik GC:

Art GC

Art的并发GC和Dalvik的并发GC有什么区别呢,初看好像2者差不多,虽然没有一直挂起线程,但是也会有暂停线程去执行标记对象的流程。通过阅读相关文档可以了解到Art并发GC对于Dalvik来说主要有三个优势点:

1、标记自身

Art在对象分配时会将新分配的对象压入到Heap类的成员变量allocation_stack_描述的Allocation Stack中去,从而可以一定程度缩减对象遍历范围。

2、预读取

对于标记Allocation Stack的内存时,会预读取接下来要遍历的对象,同时再取出来该对象后又会将该对象引用的其他对象压入栈中,直至遍历完毕。

3、减少Pause时间

在Mark阶段是不会Block其他线程的,这个阶段会有脏数据,比如Mark发现不会使用的但是这个时候又被其他线程使用的数据,在Mark阶段也会处理一些脏数据而不是留在最后Block的时候再去处理,这样也会减少后面Block阶段对于脏数据的处理的时间。

3.6 前后台GC

前台Foreground指的就是应用程序在前台运行时,而后台Background就是应用程序在后台运行时。因此,Foreground GC就是应用程序在前台运行时执行的GC,而Background就是应用程序在后台运行时执行的GC。

应用程序在前台运行时,响应性是最重要的,因此也要求执行的GC是高效的。相反,应用程序在后台运行时,响应性不是最重要的,这时候就适合用来解决堆的内存碎片问题。因此,Mark-Sweep GC适合作为Foreground GC,而Mark-Compact GC适合作为Background GC。

由于有Compact的能力存在,碎片化在Art上可以很好的被避免,这个也是Art一个很好的能力。

3.7 Art大法好

总的来看,art在gc上做的比dalvik好太多了,不光是gc的效率,减少pause时间,而且还在内存分配上对大内存的有单独的分配区域,同时还能有算法在后台做内存整理,减少内存碎片。对于开发者来说art下我们基本可以避免很多类似gc导致的卡顿问题了。另外根据谷歌自己的数据来看,Art相对Dalvik内存分配的效率提高了10倍,GC的效率提高了2-3倍。

4、GC Log

当我们想要根据GC日志来追查一些GC可能造成的卡顿时,我们需要了解GC日志的组成,不同信息代表了什么含义。

4.1 Dalvik GC日志

dalvik的日志格式基本如下:

D/dalvikvm: <GC_Reason> <Amount_freed>, <Heap_stats>, <Pause_time>, <Total_time>

gc_reason:就是我们上文提到的,是gc_alloc还是gc_concurrent,了解到不同的原因方便我们做不同的处理。

amount_freed:表示系统通过这次GC操作释放了多少内存

Heap_stats:中会显示当前内存的空闲比例以及使用情况(活动对象所占内存 / 当前程序总内存)

Pause_time:表示这次GC操作导致应用程序暂停的时间。关于这个暂停的时间,在2.3之前GC操作是不能并发进行的,也就是系统正在进行GC,那么应用程序就只能阻塞住等待GC结束。而自2.3之后,GC操作改成了并发的方式进行,就是说GC的过程中不会影响到应用程序的正常运行,但是在GC操作的开始和结束的时候会短暂阻塞一段时间,所以还有后续的一个total_time。

Total_time:表示本次GC所花费的总时间和上面的Pause_time,也就是stop all是不一样的,卡顿时间主要看上面的pause_time。

4.2 Art GC日志

I/art: <GC_Reason> <Amount_freed>, <LOS_Space_Status>, <Heap_stats>, <Pause_time>, <Total_time>

基本情况和Dalvik没有什么差别,GC的Reason更多了,还多了一个OS_Space_Status

LOS_Space_Status:Large Object Space,大对象占用的空间,这部分内存并不是分配在堆上的,但仍属于应用程序内存空间,主要用来管理 bitmap 等占内存大的对象,避免因分配大内存导致堆频繁 GC。

推荐阅读:字节跳动面试题 —— 水壶问题
2017-2020历年字节跳动Android面试真题解析(累计下载1082万次,持续更新中)

原文作者:Tmacchen
原文链接:https://zhuanlan.zhihu.com/p/24835977

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后说一下我的学习路线

其实很简单就下面这张图,含概了Android所有需要学的知识点,一共8大板块:

  1. 架构师筑基必备技能
  2. Android框架体系架构(高级UI+FrameWork源码)
  3. 360°Androidapp全方位性能调优
  4. 设计思想解读开源框架
  5. NDK模块开发
  6. 移动架构师专题项目实战环节
  7. 移动架构师不可不学习微信小程序
  8. 混合开发的flutter

Android学习的资料

我呢,把上面八大板块的分支都系统的做了一份学习系统的资料和视频,大概就下面这些,我就不全部写出来了,不然太长了影响大家的阅读。

330页PDF Android学习核心笔记(内含上面8大板块)

Android学习的系统对应视频

总结

我希望通过我自己的学习方法来帮助大家去提升技术:

  • 1、多看书、看源码和做项目,平时多种总结

  • 2、不能停留在一些基本api的使用上,应该往更深层次的方向去研究,比如activity、view的内部运行机制,比如Android内存优化,比如aidl,比如JNI等,并不仅仅停留在会用,而要通过阅读源码,理解其实现原理

  • 3、同时对架构是有一定要求的,架构是抽象的,但是设计模式是具体的,所以一定要加强下设计模式的学习

  • 4、android的方向也很多,高级UI,移动架构师,数据结构与算法和音视频FFMpeg解码,如果你对其中一项比较感兴趣,就大胆的进阶吧!

希望大家多多点赞,转发,评论加关注,你们的支持就是我继续下去的动力!加油!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

4、android的方向也很多,高级UI,移动架构师,数据结构与算法和音视频FFMpeg解码,如果你对其中一项比较感兴趣,就大胆的进阶吧!

希望大家多多点赞,转发,评论加关注,你们的支持就是我继续下去的动力!加油!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
  • 10
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值