WebSphere Application Server V8 中的垃圾收集第 1 部分 使用分代收集策略作为新的默认策略.docx
- 文档编号:29965504
- 上传时间:2023-08-03
- 格式:DOCX
- 页数:15
- 大小:121.95KB
WebSphere Application Server V8 中的垃圾收集第 1 部分 使用分代收集策略作为新的默认策略.docx
《WebSphere Application Server V8 中的垃圾收集第 1 部分 使用分代收集策略作为新的默认策略.docx》由会员分享,可在线阅读,更多相关《WebSphere Application Server V8 中的垃圾收集第 1 部分 使用分代收集策略作为新的默认策略.docx(15页珍藏版)》请在冰豆网上搜索。
WebSphereApplicationServerV8中的垃圾收集第1部分使用分代收集策略作为新的默认策略
WebSphereApplicationServerV8中的垃圾收集,第1部分:
使用分代收集策略作为新的默认策略
并非所有工作负载都是平等创建的。
不同的应用程序使用内存的方式也各不相同,因此可从不同的垃圾收集策略中受益。
IBM®Java™VirtualMachine(JVM)始终提供许多不同的GC策略,以支持各种应用程序类型。
与此同时,硬件在不断发展,软件必须适应硬件发展,以便更好地利用硬件。
在IBMWebSphere®ApplicationServerV8中,默认垃圾收集策略同时使用分代和并发收集策略。
本文将简要描述IBMJVM中提供的垃圾收集策略,并提供新默认策略的配置指南。
本文来自于IBMWebSphereDeveloperTechnicalJournal中文版。
0
评论:
ChrisBailey,Java支持架构师,IBM
关闭[x]
ChrisBailey是位于英国的HursleyParkDevelopmentLab的IBMJavaTechnologyCenter团队成员。
作为IBMJava服务和支持组织的技术架构师,他负责支持IBMSDKforJava用户交付成功的应用程序部署。
Chris还参与收集和评估新需求,交付新调试功能和工具,改进文档并提高IBMSDKforJava的质量。
CharlieGracie,GarbageCollectionTechnology团队的团队领导,IBM
关闭[x]
CharlieGracie是位于加拿大的渥太华实验室的IBMJavaTechnologyCenter的团队成员。
他毕业于NewBrunswick大学,从那里获得了理学学士学位,并于2004年加入J9VirtualMachine团队。
他目前是J9GarbageCollection团队的团队领导,负责为IBMJVM提供所有垃圾收集技术。
工作之余,Charlie喜欢玩室内和沙滩排球,热衷于参加各种户外活动。
KarlTaylor,GarbageCollectionTechnology团队的开发人员,IBM
关闭[x]
KarlTaylor是位于加拿大的渥太华实验室的IBMJavaTechnologyCenter团队的团队成员。
他拥有CarletonUniversity颁发的理学学士学位,自从J9VirtualMachine项目启动以来,他参与了该项目的多项工作。
目前,他是J9GarbageCollection团队的高级开发人员,还参与了IBM的JSR292和335研发。
工作之余,Karl是一位葡萄酒爱好者,目前正在努力通过Sommelier认证。
2011年8月25日
内容
o简介
o垃圾收集器
o调优非分代收集器堆设置
o调优分代GC
o将二者结合起来
o迁移到分代策略
o结束语
o参考资料
o评论
简介
Garbagecollection(GC)是JavaVirtualMachine(JVM)的必要组成部分,它收集没有使用的Java堆内存,以便应用程序可以继续分配新的对象。
GC的效果和性能对于应用程序性能和确定(determinism)非常重要。
IBMWebSphereApplicationServerV8附带的IBMJVM(在受支持的平台上)提供4种GC策略算法:
∙-Xgcpolicy:
optthruput
∙-Xgcpolicy:
optavgpause
∙-Xgcpolicy:
gencon
∙-Xgcpolicy:
balanced
每种算法都提供不同的性能和决定质量。
此外,WebSphereApplicationServerV8中的默认策略已从-Xgcpolicy:
optthruput更改为-Xgcpolicy:
gencon策略。
下面我们逐一检查这些策略,看看这个默认策略更改对它们有何影响。
回页首
垃圾收集器
不同应用程序自然有不同的内存使用模式。
计算密集型数字处理工作负载使用Java堆(heap)的方式不同于面向客户的高度事务型接口。
要以最佳方式处理这些不同种类的工作负载,则需要使用不同的垃圾收集策略。
IBMJVM支持许多垃圾收集策略,它允许您选择最适合您的应用程序的策略。
平行式“标记-清扫-压缩”收集器:
optthruput
最简单的垃圾收集技术可能是:
持续分配直到耗尽闲置内存,然后停止应用程序,处理整个堆。
尽管这种技术可能会生成一个非常有效的垃圾收集器,但这意味着用户程序必须能容忍收集器带来的暂停。
只关注总流量的工作负载可能会从这种策略中受益。
optthruput策略(-Xgcpolicy:
optthruput)采用的就是这种策略(参见图1)。
这个收集器)使用一种平行的“标记-清扫(mark-sweep)”算法。
简言之,这意味着收集器首先逐一访问可访问的对象,将它们标记为实时数据。
然后,第二轮访问扫除未标记的对象,将未使用的闲置内存留作新分配之用。
大部分这种工作都可以并行完成,因此收集器可以使用额外的线程(默认情况下使用的最大线程数为CPU的数量)来加快工作速度,减少应用程序的暂停时间。
图1.应用程序和收集器CPU使用情况:
optthruput
“标记-清扫”算法的问题是可能会导致碎片(fragmentation),如图2所示。
尽管可能有大量闲置内存,但如果它们只是一些小块,其间夹杂着活动对象,那么可能没有哪个碎块大到足以满足某个特定分配需求。
这个问题的解决方法是压缩(compaction)。
理论上,压缩程序会将所有活动对象都移动到堆的一端,留下一块连续的闲置空间。
这是一项昂贵的操作,因为可能会移动每个活动对象,每个经过移动的对象的指针都必须更新为新位置。
因此,通常只在万不得已时才进行压缩。
压缩也可以并行执行,但这会降低活动对象的打包效果,可能会生成几个较小的闲置空间,而不是一整块闲置空间。
图2.堆碎片
并发收集器:
optavgpause
对于愿意损失部分流量、减少暂停时间的应用程序而言,可以选择另一种策略。
optavgpause策略(-Xgcpolicy:
optavgpause)试图在停止应用程序之前尽可能多完成一些GC工作,从而缩短暂停时间(参见图3)。
这种策略也使用“标记-清扫-压缩(mark-sweep-compact)”收集器,但大部分标记和清扫工作可以在应用程序运行时执行。
根据程序的分配速度,系统试图预测下次需要执行垃圾收集的时间。
达到这个阈值时,就会启动一个并发GC。
当应用程序线程分配对象时,系统偶尔会要求它们在完成分配工作之前执行少量GC工作。
线程执行的分配工作越多,要求它完成的GC工作也越多。
与此同时,会有一个或多个背景GC线程使用闲置周期完成余下的工作。
如果已经完成所有并发工作,或者闲置内存提前耗尽,则将中止应用程序并完成收集工作。
这种暂停通常比较短,除非需要进行压缩。
由于压缩需要移动和更新活动对象,因此不能并发执行。
图3.应用程序和收集器CPU使用情况:
optavgpause
分代收集器:
gencon
很久以前,人们就注意到,创建的大多数对象只被使用一小段时间。
这是编程技术和应用程序类型所导致的结果。
许多常用Java惯用语都会创建一些将迅速弃用的帮助程序(helper)对象,比如StringBuffer/StringBuilder对象和Iterator对象。
可以分配这些对象来完成某个特定任务,任务完成后就很少会再用到这些对象。
在更大的范围内,实际上事务型应用程序也常常创建一些“一次性使用、用完作废”的对象组。
一旦返回数据库查询的响应之后,就不再需要回复、中间状态和查询本身。
这种发现导致了分代(generational)垃圾收集器的开发。
其背后的理念是:
将堆分割为多个不同区域,以不同的速度收集这些区域。
新对象被分配到一个称为托儿所(nursery)(或新空间)的区域中。
由于这个区域中的大多数对象很快都将变为垃圾,所以收集该区域最有利于恢复内存。
如果某个对象可能会存活一段时间,则会将它移动到另一个称为保留区(tenure)(或旧空间)的区域中。
这些对象不太可能变为垃圾,因此收集器很少检查它们。
对于适当的工作负载,进行垃圾收集的结果是:
由于检查的内存更少,收集更快更有效;而且,经过检查的对象被回收的比例更高一些。
收集更快意味着暂停时间更短,因此应用程序响应性也更好。
IBM的gencon策略(-Xgcpolicy:
gencon)在上述并发策略之上提供了一个分代GC(“gen-”)。
保留区空间如上所述收集,而托儿所空间使用了一个复制(copying)收集器。
这种算法的工作方式是将托儿所区域进一步细分为分配(allocate)和幸存者(survivor)空间(参见图4)。
新对象被放置到分配空间中,直到耗尽其闲置空间。
然后,应用程序会停止,分配空间中的所有活动对象都将复制到幸存者空间中。
然后这两个空间交换角色:
分配空间变为幸存者空间,幸存者空间变为分配空间,应用程序恢复运行。
如果某个对象在几轮复制之后得以幸存,则会将它移动到保留区空间中。
图4.gencon应用
理论上,这意味着托儿所空间的一半(即幸存者空间)在任何时点上都未使用。
实际上,预留为幸存者空间的内存量会根据在每次收集中幸存下来的对象的百分比进行实时调整。
如果大多数新对象都被收集(这是预期的情况),那么分配空间和幸存者空间之间的分界线就会倾斜,此时需要增加垃圾收集之前可以分配的数据量。
这种风格的收集器有一个重大好处:
通过在每次收集时移动活动对象,托儿所区域在每次收集时都被隐式压缩。
这会导致闲置空间块变得尽可能的大,但也可能会将关系密切的对象(例如String及其char[]数据)移动到临近的内存位置。
这有助于改进系统内存缓存的性能特征,从而提高应用程序本身的性能。
托儿所垃圾收集的成本与幸存的数据量有关(参见图5)。
由于预期的情况是多数对象都将是垃圾,因此一次托儿所收集通常导致很短的暂停。
尽管应该能够快速收集多数对象,但有些对象无法收集。
这意味着随着时间的推移,保留区区域中将塞满了长期存活的对象,最终导致需要对整个堆进行一次垃圾收集。
上述并发收集器使用的大部分技术在这里仍然适用。
保留区区域的标记将根据需要并发运行,而分配和收集是在托儿所区域中进行的。
在gencon策略下,保留区区域的清扫不是并发执行的,而是作为保留区主收集的一部分进行的。
图5.应用程序和收集器CPU使用情况:
gencon
基于区域的收集器:
balanced
WebSphereApplicationServerV8中添加了一个新的垃圾收集策略。
这个策略名为balanced(-Xgcpolicy:
balanced),它扩展了拥有多个不同的堆区域这个概念,将堆划分为大量区域,每个区域都可以单独处理。
本系列第2部分将详细介绍基于区域的垃圾收集的基础知识,特别是将深入讨论balanced策略。
回页首
调优非分代收集器堆设置
如何监控和分析垃圾收集器
可以通过下面两种机制监控垃圾收集器和Java堆使用情况:
∙HealthCenter实时监控工具在监控和分析垃圾收集和其他数据(包括方法执行和锁争用)方面只需很小的开销。
∙-verbose:
gc命令行选项将输出写入native_stderr.log文件,该文件可以被载入GarbageCollectionandMemoryVisualizer工具。
(也可以使用-Xverbosegclog选项将-verbose:
gc输出写入它自己的文件。
)
有关详细信息,请参阅参考资料。
要调优任何应用程序的堆大小,第一步是使用默认堆设置运行应用程序,这允许您测量开箱即用性能。
此时,如果堆闲置空间总是低于40%,或者GC暂停高于总运行时间的10%,就应该考虑增加堆大小。
最小堆大小和最大堆大小可以分别通过-Xms
用于垃圾收集的标记和清扫阶段的GC暂停时间基于堆上的活动对象的数量。
当您增加统一工作负载上的堆大小时,标记和清扫阶段将继续花费大致相同的时间完成操作。
因此,通过增加堆大小,可以增加GC暂停之间的间隔,从而为应用程序提供更多的执行时间。
如果GC由于碎片问题而执行压缩,那么增加堆大小可能有助于缓解压缩导致的长时暂停问题。
压缩阶段可能会极大地增加GC暂停时间,因此,如果压缩阶段经常出现,那么调优堆设置就能改进应用程序性能。
固定大小堆与可变大小堆
使用可变大小堆允许GC仅对堆使用应用程序必需的OS资源。
随着应用程序程序堆需求的变化,GC可以通过扩大和收缩堆做出反应。
GC只能收缩从堆末尾开始的连续内存块,因此收缩堆可能需要进行压缩。
实际的收缩和扩大阶段很快就能完成,不会明显增加GC暂停时间。
通过将最大堆大小设置为略大于常规操作所需的大小,应用程序能够通过扩大堆来处理额外的工作负载。
堆需求不变的应用程序可以通过使用固定堆大小改进GC暂停时间。
回页首
调优分代GC
如何在管理控制台中设置命令行选项
可以通过流程定义的JavaVirtualMachine面板中的常规JVM参数,在WebSphereApplicationServer管理控制台中设置Java命令行选项。
要找到JavaVirtualMachine面板,请执行以下操作:
1导航到管理控制台,从左侧面板选择Servers>ServerTypes>WebSphereapplicationservers。
2从主面板选择您的应用程序服务器。
3展开主面板右侧的JavaandProcessManagement选项,然后选择Processdefinition。
4选择右侧的JavaVirtualMachine选项。
5GenericJVMarguments文本框将在主面板底部显示。
选项添加后,需要保存并同步更改,然后重启应用程序服务器,使更改生效。
调优分代垃圾收集时,最简单的方法是将托儿所空间视为非分代垃圾收集使用的Java堆区域之外的新Java堆区域。
这样,非分代垃圾收集使用的Java堆就变成了保留区堆。
这种方法是一种保守方法:
预期的情况是保留区堆的占用率将由于托儿所空间的引入而降低,但它提供了一个安全的起点,特别是从非分代策略迁移时。
当可以监控全局(完全)收集之后的保留区堆的占用率时,就可以按照前面描述的方法来调整堆大小:
∙-Xmn
∙-Xmns
∙-Xmnx
托儿所堆大小应该是固定的,因此只需要这些选项中的一个:
-Xmn。
因此,您只需理解如何正确设置托儿所堆大小。
设置托儿所堆大小
要正确设置托儿所堆大小,首先需要考虑托儿所收集使用的机制,然后考虑随之出现的二级特征:
∙托儿所收集的工作方式是将数据从分配空间复制到幸存者空间。
复制数据是一个比较昂贵耗时的任务。
因此,托儿所收集所花费的时间由需要复制的数据量决定。
这不是说要复制的对象的数量与托儿所空间自身的大小没有影响,而是说与复制实际数据的成本相比,这些因素造成的影响相对较小。
因此,托儿所收集所花费的时间与需要复制的数据量成正比。
∙在任何给定的收集中,只有有限和固定的数据量是“实时的”。
一旦应用程序完成启动并完全填充其缓存后,托儿所堆中需要复制的“实时”数据量就由该时点需要完成的工作量来确定。
在处理事务的系统中,需要复制的实时数据量等于某个实时事务集。
例如,如果您使用支持50个并发事务发生的50个WebContainer线程来配置您的应用服务器,那么实时数据量就是与那50个事务关联的数据量。
这意味着,托儿所收集所需的时间由收集时发生的并发事务的数量的关联数据的大小决定,而不是由托儿所空间的大小决定。
这还意味着,随着托儿所空间的大小增大,托儿所收集之间的间隔时间会随之增大,但收集所需的时间不会增加。
事实上,随着托儿所空间增大,垃圾收集所需的总时间会随之降低。
图6显示,如果托儿所空间的大小低于事务集的关联实时数据的大小,因此托儿所收集之间的时间间隔低于一个事务,则必须多次复制这些数据。
图6.数据复制的平均次数与托儿所收集之间的时间间隔
随着托儿所空间大小和托儿所收集之间的时间间隔增加,需要复制的数据量通常会随之减少,垃圾收集的开销也会随之降低。
托儿所堆大小限制
IBM垃圾收集器或JVM没有对托儿所堆大小进行直接限制;事实上,托儿所堆大小有时被设置为10GB甚至100GB。
但是,操作系统在Java进程使用的虚拟内存、进程地址空间以及足够的物理内存(RAM)的可用性方面有一些限制。
一个32位进程在每个平台上的操作系统限制如图7所示。
图7.按操作系统列示的32位地址空间
对64位进程的限制要严格得多。
由于可寻址内存的范围从数百到数十亿GB,可用物理内存(RAM)的限制变得更加重要。
回页首
将二者结合起来
如上所述,最简单的方法是将托儿所空间视为一个额外的内存空间。
但是,托儿所堆和保留区堆实际上都被分配为单个连续内存段,它们的大小可通过-Xmx设置进行控制。
如果只使用-Xmx设置,则-Xmx值的25%用于最大托儿所堆大小,托儿所堆大小允许在那25%之内进行伸缩。
下面提供了Java堆布局,如图8所示。
图8.默认堆布局
但是,您应该将托儿所堆大小固定为一个较大的值,以最小化垃圾收集花费的时间,增强保留区堆,使其根据占用率重置自身大小,从而提高弹性。
因此,首选的Java堆布局如图9所示。
图9.推荐的堆布局
要实现这个布局,托儿所空间和保留区空间的最小和最大堆大小的值应该设置如下:
各个托儿所空间大小的最大和最小值都相等,而各个保留区空间大小的最小和最大值各不相同。
例如,如果您想拥有一个256MB的托儿所堆大小,而保留区堆大小介于756MB和1024MB之间,则这些值应该为:
-Xmns256M
-Xmnx256M
-Xmos756M
-Xmox1024M
回页首
迁移到分代策略
由于WebSphereApplicationServerV8中的默认GC策略已经从optthruput变为gencon,因此需要调整以前选择的调优参数。
主要问题是更改堆大小来补偿托儿所空间。
以前在optthruput策略中,以1G堆大小(即-Xmx1G)运行正常的程序在使用768M保留区空间和256M托儿所空间运行时可能会出现问题。
前面介绍的技术将有助于您选择新的堆参数。
还有一些不太明显的情况,gencon可能会表现出不同的行为。
由于类通常是长期存活的对象,因此可以将它们直接分配到保留区空间。
因此,类卸载只能是保留区收集的一部分。
如果应用程序非常依赖短期存活的类加载器,且托儿所收集能够及时处理其他已分配对象,那么保留区收集可能不会频繁发生。
这意味着,类和类加载器的数量将持续增长,这可能会增加本机内存上的压力,而且会在需要进行保留区收集时导致收集时间过长,这是因为有太多的类卸载工作需要完成。
如果出现这个问题,有两种解决方法。
第一种方法是在出现大量类加载器时鼓励进行额外的保留区收集。
命令行选项-Xgc:
classUnloadingKickoffThreshold=
因此,如果指定-Xgc:
classUnloadingKickoffThreshold=100,那么托儿所收集会仔细观察,每当自上次保留区收集以来新创建的类加载器数量达到100时,就会启动一次并发保留区收集。
第二种方法是改为使用另一种GC策略。
类似的问题可能会出现在引用对象(例如java.lang.ref.Reference的子类)和使用finalize()方法的对象上。
如果这两种对象存活的时间足够长,在变得无法访问之前被移动到保留区空间中,那么可能会经过很长时间以后才会运行保留区收集,“发现”这个对象已经死亡。
如果这些对象占用着大型或稀有本机资源,就有可能导致出现问题。
我们将这种对象戏称为“冰山”对象:
表面上它们只占用很小的Java堆大小,但下面隐藏着巨大的本机资源,垃圾收集器看不到。
就像面对真正的冰山一样,最好的策略是尽可能远离它们。
即使使用其他GC策略,也无法保证能够探测到可终结的对象,并及时运行它的终止程序(finalizer)。
如果它们占用稀有资源,尽可能地手动释放它们可能是最佳策略。
更改策略
默认策略应该能为多数工作负载提供足够的性能,但它可能不是某个特殊应用程序的理想选择。
类似“批作业”的应用程序初始化状态并加载要处理的数据。
这些对象中的大部分将在作业期间存活,只有少数几个额外对象是在作业运行时创建的。
这种工作负载适合optthruput模式,因为预期的情况是:
在任务完成之前,几乎没有垃圾。
另一种类似情况是,如果作业很快完成或只分配很少的对象,那么只要堆大小适当,作业运行就不需要垃圾收集。
在上述这些情况下,optthruput收集器的最小开销会让您做出最佳选择。
相比之下,事务型应用程序不断创建并启用对象组。
在这个上下文中,术语“事务”主要使用字面意义(比如数据库更新或电子商务采购)或者采用更宽泛的意义,比如一项独立工作。
举例来说,服务一个Web页可以视为一个事务。
客户机提交一个URL,服务器计算页面内容并将其发送给客户机。
一旦客户机接收到页面,服务器就可以丢弃已计算的数据。
为了进一步阐述这个定义,我们来看一个标准用户界面。
用户单击Save按钮之后,系统会打开一个文件对话框,以便用户导航文件系统,为文档选择一个位置。
一旦用户关闭对话框,就不再需要所有中间状态。
实质上,有些批作业甚至也是事务型的。
假设一个任务正在为一些大型图像文件创建缩略图,那么该作业看起来似乎是一个大型批作业,但在内部,作业分别处理每个图像,每个处理都形成一个“事务”。
对于这类工作负载,gencon模式应该能提供好处。
optavgpause模式介于二者之间。
这种模式适用的应用程序的特点是:
拥有大量长期存活的数据,这些数据随着程序运行缓慢更改。
对于工作负载而言,这种模式比较少见。
通常,长期存活的数据要么从不更改,要么频繁更改。
也就是说,如果系统拥有缓慢演变的数据,且这些数据创建的中间对象也不多,那么这种系统就适合使用这个策略。
由于前面讨论的某种原因而不能在gencon策略下有效运行的程序可能会受益于optavgpause的并发性。
回页首
结束语
本文简要描述了WebSphereApplicationServerV
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- WebSphere Application Server V8 中的垃圾收集第 部分 使用分代收集策略作为新的默认策略 中的 垃圾 收集 使用 策略 作为 默认
链接地址:https://www.bdocx.com/doc/29965504.html