飞码网-免费源码博客分享网站

点击这里给我发消息

Eclipse OpenJ9中的内存管理 |-Java教程

飞码网-免费源码博客分享网站 爱上飞码网—https://www.codefrees.com— 飞码网-matlab-python-C++ 爱上飞码网—https://www.codefrees.com— 飞码网-免费源码博客分享网站

自将OpenJ9 Java虚拟机(JVM)发布给开源社区以来,我们收到了许多与垃圾收集(GC)策略有关的查询,这些策略可用于管理运行时堆。这些通常涉及堆配置,性能,调整功能,最重要的是,有关配置和调整堆以使其最适合其应用程序特征的准则。

本文从概述可用的GC策略和堆配置开始,着重解决了其中一些问题,重点是默认的GC策略gencon。查看两种常见的应用程序类别,并了解它们的特征如何映射到GC策略,以及如何调整这些策略以优化应用程序性能而不会引起内存管理的麻烦。

垃圾收集

OpenJ9提供了几种不同的GC策略,每种策略专门用于具有特定堆配置和一个或多个收集器的操作。下表总结了这些策略:

GC政策 堆配置 收藏家
Gencon 代(保育/任期) 清除剂,并发标记,全球
均衡 世代(多个区域) 增量世代
OptAvgPause 平坦的 并发标记,全球
OptThruput 平坦的 全球的
节拍器 隔离的 即时的

所有OpenJ9 GC策略均支持64位平台上的压缩引用,如果总堆大小不超过63gb,则该压缩引用会将堆指针压缩为32位。需要更多堆空间的应用程序可以放弃压缩的指针,并在操作系统和可用系统RAM施加的范围内选择任何堆大小。

OpenJ9 Java应用程序可以使用标准Xms和Xmx命令行选项来设置初始和最大堆范围,从而确定任何策略的初始和最大堆大小。

策略选择和调整

对OpenJ9 JVM选择适当的GC策略并调整堆的指导首先是对应用程序动态的深入了解,并观察应用程序在启动和稳定状态下如何与堆交互的指导。为了帮助解决这个问题,所有OpenJ9 GC策略都经过专门工具收集各种与GC相关的度量标准数据,以便在GC日志中进行报告。

要为OpenJ9 Java运行时启用GC日志记录,请包括-verbose:gc命令行选项。然后,当将GC日志加载到Eclipse的垃圾收集器和内存可视化器(GCMV)插件中时,可以交互式地可视化检测到的度量标准数据。还可以通过某些在线服务(例如GCEasy)来分析OpenJ9 Java GC日志。

Gencon

OpenJ9 Java的默认GC策略是gencon,它非常适合大多数Java应用程序,并且通常是性能最高的。此策略配置世代堆,分为育苗区和保育区。在托儿所中分配新对象,直到其达到90%的满度并触发托儿所集合。世代堆中托儿所的默认大小为整个堆的25%。可以使用Xmn(固定的托儿所大小)或Xmns和Xmnx(可变的托儿所大小)选项进行调整。

下图显示了托儿所收集开始时的世代堆。应用程序已从中分配新对象的倾斜(撤离)子空间已填充,因此必须撤离。将幼小的对象撤离到保育室的幸存者子空间,将已从保育室中老化的对象撤离到保有权空间。

世代堆

大多数对象的生命周期都很短,可以在托儿所集合中快速回收,而更多持久性对象则从托儿所迁移到保有权区域。通常,新对象在保留14个托儿所集合后会进入使用期限,但是如果分配率很高,则可以减少使用期限。权属空间将定期填充,触发全局标记以标记活动对象并从权属区域清除死对象。托儿所收集通常是频繁的且持续时间较短,整体收集应相对较少且持续时间可能更长,尤其是在保有权区域变得支离破碎并需要压实的情况下。

世代(保育)和全局(任期)收集器是世界各地的收集器-所有应用程序线程在收集期间暂停。但是,并发标记收集器与应用程序线程一起运行,以监视对象的保有率。它会定期使用应用程序线程来执行短暂的标记工作,以预见即将到来的全局集合,从而减少了全局集合的暂停时间。

理想情况下,苗圃将足够大,可以包含应用程序瞬时活动集的多次迭代。保有权空间将足以容纳所有应用程序的持久性数据,并有足够的空间容纳中等寿命的对象。通常,全球收集的频率应限制为每100个托儿所收集约1个。通过选择合理的堆大小(默认苗圃大小预设为堆的25%)并通过启用GC日志记录的启动,稳定和高峰工作负载运行应用程序,可以获得经验反馈。然后,生成的日志可以帮助优化堆和托儿所的大小,直到获得可接受的性能水平。

为了获得最佳性能,应调整苗圃的大小,以减少临时物体的保有率。在GC日志中报告的倾斜比率度量标准,确定了为苗圃集合之间分配新对象而保留的苗圃的比例。在整个应用程序生命周期中,应将其维持在尽可能高的水平(最高90%)。如果倾斜率太低,则瞬变对象将更有可能溢出到权属空间中,从而触发更频繁的全局收集。在这种情况下,请考虑增加苗圃的大小,直到稳定状态下的倾斜率超过70%。或者,如果已调整托儿所的大小以获得稳定的高倾斜率,则可以通过在保持托儿所大小固定的同时增加堆的大小来降低全局收集的速率。

如果全局暂停时间过于频繁而无法接受的长时间,则可以通过减少为权属空间保留的堆的比例来减少最大暂停时间,在更频繁的全局集合中换取较短的平均暂停时间。这对于具有紧凑活动集的应用程序最为有效,也就是说,当大约在同一时间分配的对象倾向于在大约同一时间从活动集中退出时。管理随时间分布不太紧密的活动集的应用程序将在使用权空间中遇到某种程度的碎片化,最终将迫使对使用权空间进行昂贵的压缩。

通过活动的JNI(Java本机接口)关键操作固定在托儿所中的对象的存在将防止发生托儿所收集。在这种情况下,通常会触发托儿所收集的分配失败将强制进行全局收集。使用gencon广泛使用JNI关键操作的应用程序应密切监视GC日志,以确定JNI活动是否正在损害GC性能。

案例分析

下图是启动和稳定状态下来自xml验证服务的gencon指标的GCMV图。堆大小固定为1280 mb,默认的25%(320 mb)保留给苗圃。这显示了大约1000个苗圃集合(清除时间),平均持续时间约为41毫秒(约占运行时间的20%)。

gencon指标的GMCV图

还有10个全局集合,但是它们的持续时间很短,因为大多数使用权的对象都是瞬态,已从跨越苗圃集合的验证周期中移出苗圃。从不稳定的保有权年龄和倾斜率动态可以明显地看出这一点。这些长期的瞬变很快被清除,全局收集占GC总暂停时间的<1%。在这种情况下,可以通过将苗圃大小增加一倍至640 mb,同时将总堆大小保持在1280 mb的方式来减少苗圃集合中消耗的总时间。通过此调整,服务可以更平稳地运行,如下面的GCMV图所示。

调整后的Gencon指标的GMCV图

在此配置中,大多数验证周期会在其活动集中的对象仍位于苗圃中的同时完成,并且暂时对象溢出到权属空间中的可能性很小。保有权年龄的动态模式稳定在4左右,倾斜比率将上限推高(90%),这表明在不超过4个托儿所集合之后,几乎所有对象都从活着的环境中掉落,存活下来的活体中只有不到10%与每一代。在采样的运行时间中,消除了全局周期,苗圃收集的数量减少到<500,平均苗圃收集的持续时间减少到大约38毫秒。在这种情况下,GC消耗的总运行时间不到8%。

均衡

平衡策略适用于在64位平台上需要大堆(> 64 mb)的应用程序。对于使用gencon遇到不可接受的暂停时间的应用程序,此策略可能是一个很好的选择。同样,增量世代收集器可以在支持平台上利用非统一内存体系结构(NUMA)功能来优化收集吞吐量。

增量世代收集器用于管理被拆分为大量(通常为一千个或两千个)区域的堆。每个区域的年龄范围从0(最小)到24(最大)。从年龄为0或1的区域(包括伊甸园空间)的子集分配新对象。增量世代堆中伊甸园空间的默认大小为整个堆的25%。可以使用Xmn(固定伊甸园大小)或Xmns和Xmnx(可变伊甸园大小)选项进行调整。中年区域充当幸存者区域,以接收从较年轻区域转发来的活物。最大年龄(24)的区域总体上类似于世代堆中的保有权空间。

下图显示了增量世代堆的概念图。

增量世代堆的概念视图

增量世代收集器按三个主要阶段或周期进行。当被选择用于结算的区域的一个子集在增量部分全局循环(的PGC)的复制代发生。该区域始终包括伊甸园地区,但如果年龄在具有历史高死亡率的年龄组中,则还可以包括<24岁的较早地区。中间年龄为N的可收集区域内的物体被疏散到年龄为N + 1的幸存者区域。PGC收集集中从未包含年龄为24岁的区域,而是可以将其包含在全局GC(GGC)循环中以进行压缩,以标记和清除需要进行碎片整理的整个堆和紧凑区域。

随着时间的流逝,瞬态物体从活动场景中掉落​​,存活的生存区域变得稀缺。在某个时候,全局标记阶段(GMP)将开始标记并清除整个堆。GMP的每个增量之后都是PGC的增量,因此可以在GMP期间和之后收集,清除和回收在清除后稀疏的区域。

平衡GC策略对阵列使用特殊表示,在选择GC策略时应考虑这些特殊表示。与gencon一样,可以包含在单个区域中的数组在堆中连续表示。较大的数组在堆中具有不连续的表示形式,由包含对象标头的主干和包含0个或多个指向arraylet的指针的数组组成,其中每个arraylet占据整个区域。使用gencon,大型阵列始终具有连续的表示形式,并且必须翻转通过苗圃,也就是说,如果它们达到保有权年龄,它们将被复制多达14次。使用平衡GC策略,仅需要在PGC循环中复制阵列主干和与主干相邻的其余阵列元素。

与gencon一样,固定用于JNI访问的对象可防止将包含区域包含在PGC收集集中。此外,对于通过JNI导出大型阵列的应用程序而言,重要的是,大型阵列的不连续表示要求必须连续重构整个阵列才能进行JNI访问,如果经常使用这种类型的访问,这可能会给系统带来沉重的负担。

案例分析

下面的GCMV图说明了均衡策略在经过良好调整的增量世代堆中的操作。在这种情况下,该应用程序是一个数据库服务器,该服务器维护一个内存数据库,该数据库将在服务器启动时加载。绿色实线(收集后的空闲堆)表示仅包含在空白区域中的空闲堆的数量–此指标未包括的部分充满或碎片区域中的空闲内存。

精心调整的增量世代堆中平衡策略的操作的GCMV图

与内存数据库相关联的对象在伊甸园空间中被早期实例化,并迅速迁移到逐渐变老的区域,直到它们达到最大年龄为止,这解释了在启动阶段从伊甸园和中间区域复制的相对大量的材料(30-40)秒)。在稳定状态下,服务器处理少量活动,其中分配了短暂的临时对象以支持数据库查询和批处理更新。这些操作会影响核心数据库,从而导致持久性对象迁移到最大年龄的速率相对较低,并且伊​​甸园空间的转换速率适中。

逃离苗圃的瞬态物体堆积在中等年龄的区域,这些区域偶尔会在PGC周期中清除。随着时间的流逝,中间区域将填满,直到启动一系列增量全局标记阶段(GMP)周期为止。这些与PGC周期交替进行,直到标记完成为止,这时将清除整个堆以清除所有区域中的死对象。这将使某些区域稀疏地充满活动物体。随后的PGC循环继续清除这些区域,从而释放了更多堆区域,以供循环回伊甸园空间。在每个GMP阶段完成后,自由堆区域的持续增加在GCMV曲线中反映了此活动。

有关平衡GC策略的更多信息,请参阅平衡垃圾收集作为新选项。

Optavgpause和optthruput

optavgpause和optthruput策略使用全局收集器来管理由单个区域组成的扁平堆。该应用程序将一直运行到堆耗尽为止,并且全局收集器将开始运行以标记和清除堆。此外,如果堆变得碎片化,则全局收集器将压缩堆。

这些策略最适合短寿命的应用程序以及涉及寿命短的并发会话的长期运行的服务。具有足够堆大小的短期应用程序通常无需压缩即可完成,并且在分配会话绑定的对象并从短重叠集群中退出活动集中时,扁平堆的碎片分解速度会更慢。

optavgpause策略采用同步标记作为gencon的标记,以预测全球收集并在世界停止全球收集阶段之前启动一些标记。这样可以减少由于GC活动而长时间中断服务的可能性。

optthruput策略禁止并发标记,最适合可以忍受更长的暂停以获得更好的整体吞吐量的应用程序。

案例分析

为gencon提供的xml验证服务可以在optavgpause或optthrupt上很好地运行,因为每个文档的并发活动对象集是短命的,并且在验证完成后不会在堆中留下任何痕迹。下面的GCMV图显示此服务在optavgpause的1280 mb固定堆中运行约6分钟。

XML验证服务的GCMV图

全球大约有600个短时间(约40毫秒)的集合,在稳定状态下将正常数量的可用堆保持在1100 mb左右,消耗的时间不到总运行时间的7%。可用堆的扁平线模式表明工作循环(在这种情况下为每个文档)被很好地包含并且在堆中几乎没有残留,因此该服务可以长时间使用optavgpause或optthruput运行,而不会产生压缩。

节拍器

节拍器策略在64位AIX®和Linux™/ x86_64平台上可用。它旨在用于需要精确的收集暂停时间上限的应用程序中。实时收集器以短暂的可中断脉冲串运行,并在暂停持续时间上预设了上限。

实时堆是作为连续范围的RAM分配的,这些RAM分为大小相等的小区域,通常约为64kb。数组表示为具有指向包含该数组元素的一系列区域的脊线的arraylet。每个区域为空或仅包含相同大小的对象或arraylet。该组织简化了新对象的分配和可用堆空间的合并,从而使实时收集器可以在支持一致的服务级别的同时保持GC吞吐量。对于平衡GC策略,JNI对数组数据的访问可能涉及将数组重组为连续数组,这可能会严重降低实时操作。

通过使用-Xgc:targetPauseTime = N(毫秒)选择目标暂停时间,可以限制暂停时间。通过使用Xgc:targetUtilization = T(%)选择目标利用率来保留应用程序带宽,该目标利用率表示为收集暂停之间应用程序所需的运行时间百分比。合理的利用率目标通常在50-80%的范围内,但可以根据应用程序的对象分配率特性设置为90%。

实际上,实时收集器可能无法使用选定的约束来维护堆,并且可能有必要调整堆大小或目标利用率或暂停时间以实现可接受的运行时配置。

有关实时堆和节拍器GC策略的更多信息,请参见实时垃圾收集。

选择GC策略

OpenJ9 Java的默认GC策略是gencon,它管理世代堆。这是OpenJ9的性能最高的收集器,可以对其进行调整以获得大多数应用程序的平稳运行时特征。但是某些应用程序具有非典型的动态特性或问题,使它们更适合于使用备用收集器进行操作。

一个问题是频繁使用JNI关键操作来导出堆上结构以供本机代码访问,这可能会禁止gencon苗圃收集并​​从PGC收集集中排除某些平衡区域。另一个是在gencon苗圃中存在非常大的对象(通常是数组)。这些对象在两个苗圃子空间之间反复翻转,直到它们退出活动集或被保留。大量使用大型阵列的应用程序可以使用平衡收集策略来实现更好的整体性能,因为平衡收集器可以适当地老化大型阵列,而无需将它们一代又一代地复制。

经常使用类加载器的应用程序在gencon上可能会遇到性能欠佳的情况,因为这些对象只能在全局收集期间卸载。因此,即使与类加载器的短暂交互也可能导致它们在使用权空间中累积,从而导致更频繁地进行更长时间的全局收集。平衡的策略可以逐步卸载类加载器,对于gencon遇到类加载器相关问题的服务,应考虑采用平衡策略。平衡的策略可能会比gencon提供更稳定和可靠的性能,这主要是由于采用了渐进式的碎片整理方法。由于使用了gencon压缩,经历了令人无法接受的长时间收集暂停的应用程序可能会在平衡策略下运行得更加顺畅。

具有工作周期且包含完备工作集的应用程序可能会非常适合使用optavgpause或optthruput策略与平面堆一起运行,在这些工作周期中,分配好的对象通常会一起从活动集中丢失。

飞码网-免费源码博客分享网站 爱上飞码网—https://www.codefrees.com— 飞码网-matlab-python-C++ 爱上飞码网—https://www.codefrees.com— 飞码网-免费源码博客分享网站
赞 ()
内容页底部广告位3
留言与评论(共有 0 条评论)
   
验证码: