前言
在作者的上一篇文章《Android R常见GC类型与问题案例》中,对Demo应用的Heap堆结构与Space类型及相对应内存分配算法做了简要的探究,同时对Android R机器运行中常见的GC类型和具体卡顿案例进行了细致的梳理,对Android系统和应用开发人员了解学习ART GC运行策略和优化具体GC类问题具有一定的借鉴参考意义。
承接上一篇文章,本文将对JVM垃圾回收和CC回收器简单介绍,因文章篇幅原因,对CC回收器的细节本文不过多展开,敬请期待作者下一篇对CC回收器具体实现分析的文章,本文重点介绍GC的任务和工程化的挑战,以及CC回收器的特点和优势。 术语
为了后面叙述方便,首先明确以下名词的含义:
Concurrent: 并发,指回收线程和应用线程可同时运行
Parallel: 并行,指多个回收线程同时进行垃圾回收工作
Collector: 进行垃圾回收的线程
Mutator: 修改器线程,指任何可以修改Heap的线程,一般指应用业务线程
RootSet: 根集对象集合(全局类、线程上下文类)
RememberSet: 记忆集,一种数据结构记录堆内跨代、跨区引用
CardTable: 记忆集的一种实现,一块连续内存地址段对应一个Card,当内存段内的对象存在跨区、跨代引用,标记为dirty_card。
Tracing: 可达性分析的追踪过程,从根对象标记引用链上的所有对象
PauseTime: GC时挂起Mutator线程的时间,CC只有一次Pause,在FlipThreadRoots中
CMS: Concurrent Mark Sweep--并发标记清除回收器
CC: Concurrent Copying--并发复制回收器
Partial GC: 部分回收,CC中指回收所有region和其关联的space
Sticky\Young\Minor GC: 新生代回收,CC中指只回收新生代region
Full GC: 全堆回收
起始、原始快照:追踪过程中,记录被删除的引用,将被删除的引用指向的对象加入标记栈,最后再追踪下此对象(并发阶段死亡的对象也会标记为存活,即漂浮垃圾,下次GC再回收)-G1、CC采用
增量更新:追踪过程中,记录新增引用,将引用被修改过的对象加入到标记栈,最终再追踪下此对象,并发阶段死亡对象能被回收,漂浮垃圾少,但需要一个额外的STW最终标记-CMS采用
在李晓峰的《虚拟机设计与实现:以JVM为例》一书中,提出合格的回收器必须做到的三个方面:
正确性:GC不会丢失任何存活对象。任何需要的对象都不能被当成垃圾对象被回收,否则可能出现逻辑错误和进程崩溃。
进步性:GC不会保留任何垃圾对象太长时间。即垃圾对象最终都将被清除,短暂地保留一些漂浮垃圾不是问题。
可结束:确保Tracing阶段可结束。Tracing阶段的遍历或递归不会出现死循环。
在GC算法的业界研究和工程化应用中,重点是如何做到:
更小的PauseTime,对应的提出并发回收、并行回收和分代回收
更高的吞吐量,吞吐量=回收的内存/回收耗时
更低的内存分配耗时,常见分配算法BumpPointer\Dlmalloc\Rosmalloc\FreeList
更少的内存碎片(高效内存整理),如后台进程进行内存整理,对拆分为多个region管理等
更高的内存利用率,如可达分析与引用计数混合实现,精准的垃圾回收区域策略等
更小的GC数据内存占用开销,如CardTable\MarkBitmap的实现
漂浮垃圾回收策略和对象消失的处理手段,对应增量更新、起始快照的实现
自动回收进程运行过程中不再需要的垃圾对象(也称孤立对象)。在这个任务中有几个重点:
l 垃圾对象的判定
l 垃圾回收实现方式
l 降低GC对业务的影响(对应上一条:GC的难题)
1)垃圾对象的判定垃圾对象也称为死亡或孤立对象,相反的则是存活或活跃对象。要寻找垃圾对象,首先的前提:所有对象只有两种状态,不是存活就是死亡。所有对象的合集为存活对象合集和垃圾对象合集组成,没有第三种集合。
主流的有两种算法来判定垃圾对象:
引用关系 图示
A) 引用计数法(RC:Reference counting)
引用计数法的思想是确定哪些对象是死的,在对象从存活到死亡的过程中回收内存,因对象死亡时间不定,所以引用计数类GC具有时刻回收、内存利用率高的特点。
如上图示,引用计数法类的GC会记录每个对象的引用次数,当引用次数为0时,代表此对象没有被任何对象引用,即认为是垃圾对象。引用计数类GC有以下优势:
实现简单
引用减少至0时,实时回收内存,内存利用率高
回收操作可并发运行,无需暂停应用线程除了优势,在实现运用上也有以下主要弊端:
对象环状循环引用(见上图右侧),此类型的对象无法被回收(开源社区有一些复杂方案能解决此场景)
Space overhead: 每个对象需要格外空间存储引用次数
Speed overhead: 每次引用修改需要增加指令,且多线程情况下需要加锁保证原子操作因上诉弊端,尤其是环状引用和overhead方面,主流工程化应用的GC都没有选择引用计数法,而是选择可达性分析法。
B) 可达性分析法
可达性分析法的思想是找出哪些对象是活的,活的对象确定后,其他的都是死亡对象(垃圾对象),通过一次批处理完整的清除垃圾对象,回收垃圾对象占用的内存。因此在一次GC的垃圾对象回收前,可以认为所有对象都是存活对象。
如上图示,左边已确定的根集对象出发直接引用和间接引用到的对象都是存活对象,因为根集中的根对象是系统运行和业务逻辑必须的对象,被根对象直接或间接引用的对象当然需要保留。
确认到所有从根集对象直接和间接的对象合集(引用关系图\对象邻接图)后,其他与根对象无关联的对象则被判定为垃圾对象,可以直接进行回收。
可达性分析类GC有以下优势:
不存在循环引用问题
不存在引用计数法的空间和运行时开销
当然,可达性分析法也有弊端:
内存利用率低(在GC回收内存前,垃圾对象占用的内存无法复用)
设计复杂,若需要支持并发回收需要额外数据结构支撑
PauseTime: 根集枚举与引用Tracing过程一般需要暂停应用线程至少一次,大部分回收器要暂停2-3次
虽然引用计数法和可达性分析法的思想和实现完全不同,但两者其实是互补关系,在业界不乏一些优秀的GC回收器实现整合了两个算法的优点,来提高内存利用率和减小暂停时间。
*这篇文章分析的CC回收器使用的是可达性分析法。
2)垃圾回收的实现方式
在周志明的《深入理解Java虚拟机》一书中,展示了下面几种经典垃圾回收算法:
建立在以下三个假说之上
弱分代假说:绝大多数对象都是朝生夕死
强分代假说:熬过越多次GC过程的对象越难以死亡 跨代引用假说:
跨代引用相对于同代引用来说仅占极少数
因此,商业虚拟机中一般都会将Java Heap堆划分成不同的区域,按照年龄大小将对象聚集在一起,匹配有差异化的回收策略,以提高GC吞吐量和提高内存利用率。
特点:实现简单,GC耗时短,但会产生大量内存碎片
特点:解决内存碎片问题,有对象复制的开销,且牺牲一半可用内存
特点:不存在内存碎片和内存浪费,对象复制与引用更新开销巨大,整理阶段一般需要挂起应用线程
a. ART中各回收器的算法体现在Android 7(N)及以前的几个Android版本中,应用在前台时使用CMS(并发标记清除)回收器,在前台时重点关注内存回收速度。应用在后台时使用HSC(同构空间压缩)回收器,实质是标记-整理算法的一种实现。
在Android 8(O)之后,应用在前后台都是用CC(并发复制)回收器,应用在前台也能整理内存,减少内存碎片化。应用在后台时,可以最大程度地进行内存整理。在Android 10(Q)版本重新引入了分代回收,每个的Region可能是老年代或者新生代。
Android各版本回收器性能对比(数据源自Google I/O 19)
表中对比发现,CC回收器在内存分配速度、内存整理等方面都有全面的提升,本文后续章节将探究CC回收器的实现原理和策略。
3)降低GC对业务的影响
基于可达性分析实现的GC无法避免的是PauseTime(STW:stop the world),主流的回收器都在致力于减少PauseTime。不支持并发的回收器进行垃圾回收时,需要先暂停进程的所有线程,等待GC线程进行根集遍历(Root visit)、Tracing标记和回收后,进程才能恢复运行。如此长的PauseTime对于用户体验是非常致命的。
为了优化PauseTime,商用回收器基本都采用并发(Concurrent)实现,比如CMS\G1\CC等。
并发机制可以极大的减少PauseTime,一般只需要在枚举线程上下文的根对象才需要暂停线程,比如ART虚拟机的CC回收器只在枚举线程根对象时暂停一次。
并发也带来了实现逻辑的复杂化,需要增加多个关键数据和机制来维护并发期间的数据准确。主要是解决以下的难题:
并发期间引用更新的处理,Collector Tracing过程中Mutator持续修改引用
存在跨代引用和跨区引用,并持续被Mutator修改
在CC回收器实现中,采用并发机制,极大地减少了PauseTime,依据google官方数据,PauseTime平均为0.4ms,且不随堆大小而变化,只与Roots的数量有关。
CC回收器GC过程 图示
CC回收器并无独创性的理论突破,借鉴的是开源社区成熟的GC理论和应用成果,结合Android设备和堆内存特点进行的实现应用。主要优化内存分配速度与内存碎片,核心理论突破是将整个堆分为多个同等大小的内存段,化整为零再分而治之。
先回顾下采用CC回收器的app堆结构图。 Demo app堆结构 图示
1)回收流程概述
InitializePhase,初始化统计量,设置标记等。
MarkingPhase,遍历所有Root根集,将根集对象直接引用对象压入mark_stack,并发标记存活对象记录在mark_bitmap中(此阶段只用于确定回收区域,StickyGC和ExplicitGC不需要)。
FlipThreadRoots,依据上一阶段的标记信息,确定回收区域(倾向于回收垃圾对象多的region),回收区域设置为from_space。
CopyingPhase,处理跨代、跨区引用的dirty_card,将from_space中的存活对象拷贝至to_space,更新引用等。
ReclaimPhase,释放from_space的空间,重置为to_space。
2)PartialGC与StickyGC流程图示
3)涉及算法
整个堆划分为多个同样大小的Region(256KB),Region内分配内存使用最高效的BumpPointer指针碰撞算法,缺点是无法单独释放某个对象的内存(漂浮垃圾无法避免),只能整个释放Region占用的空间。
全局层面为标记-整理算法,两个Region间为标记-复制算法。有效地减少内存碎片。
写屏障支持,用CardTable实现RememberSet,记录跨代/特殊Space与RegionSpace间的引用。
由CardTable,转发指针,起始快照,目标空间不变(只访问to_space对象)等特性支持。
4)参考设计
借鉴G1/Shenandoah回收器思想,化整为零,分代收集。
5)基础原理
修改对象的引用型成员变量时执行一段特殊代码。CC中引用修改会将对象关联的Card标记为Dirty,用于记录自上次GC之后和GC并发期间的引用变化。
读取对象的引用型成员变量访问目标对象时执行一段特殊代码。CC中通过目标对象的monitor_成员变量关联的LockWord对象判断目标对象是否被拷贝。未拷贝则Mutator将目标对象进行拷贝并修改原对象的LockWord使其指向新对象,且将对象的引用修正为新的目标对象。
被拷贝后的from_space原对象LockWord配置转发指针,之后所有访问原对象都会自动指向to_space新对象。
6)优势
指针碰撞分配,贡献最高的内存分配速度。
前后台内存整理,更少的内存碎片,可控的漂浮垃圾数量。
更灵活的内存管理单位,提升内存利用率,相比CMS降低平均32%的堆占用(google官方数据)。
更精准的分代垃圾回收策略,提升吞吐量(回收效率),减少PauseTime。
7)不足
预留两倍堆空间的内存地址(32位应用影响明显,增加虚拟内存地址不足OOM概率)。
并发复制过程耗时随堆大小、对象数递增,耗时较长。
Mutator线程参与对象拷贝和Tracing,存在对象移动风暴。
读写互斥锁与锁堆特殊场景阻塞应用线程。
无法单独释放某个对象的内存,并发过程中新增对象默认为存活,存在一定的漂浮垃圾。
本文重点着力于阐述GC并发所面对的问题和对应的优化手段,结合Android ART虚拟机中CC回收器的实现原理和回收流程,简短的概述文章,希望读者看完能增加对GC的认识。GC理论发展几十年,依靠CPU算力提升和以空间换时间等经典思想,逐步地将GC对应用线程的影响一步步降低。有个说法JAVA开发者无需过多关注GC,但系统开发者和应用架构师掌握虚拟机内存管理机制是很有必要的,对于指导业务优化和实现高级功能都有助益。
作者下一篇文章将CC回收器具体代码进一步剖析,Stay Tuned!
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/omRr8_EDtRnmCnl-1Dw77w
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。