JVM杂项

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chenpeng19910926/article/details/86500716

我们启动后使用命令查看垃圾回收情况,

命令:ps -ef|grep PermGCTest|grep -v grep | awk '{print$2}'|xargs -I{} jstat -gc '{}' 1000 200

Dozer :https://www.jianshu.com/p/bf8f0e8aee23

CMS参数学习:

-XX:+UseConcMarkSweepGC: 

-XX:+ParallelCMSThreads: 设定 CMS 的线程数量。

-XX:+CMSClassUnloadingEnabled:允许对类元数据进行回收。

-XX:CMSInitiatingOccupancyFraction=50 设置的是超过50%才进行老年代fullgc, 因此确定非老年代被占满造成的,默认是 68

-XX:CMSInitiatingPermOccupancyFraction=92, 即perm占用高于92%即发生CMS GC, 判定由于perm区占用较高造成,启动 CMS 回收 (前提是-XX:+CMSClassUnloadingEnabled 激活了)。

-XX:+UseCMSCompactAtFullCollection 参数可以使 CMS 在垃圾收集完成后,进行一次内存碎片整理。

-XX:CMSFullGCsBeforeCompaction 参数可以用于设定进行多少次 CMS 回收后,进行一次内存压缩。

-XX:UseCMSInitatingOccupancyOnly:表示只在到达阈值的时候,才进行 CMS 回收。

-XX:+CMSIncrementalMode:使用增量模式,比较适合单 CPU。

-XX:+CMSScavengeBeforeRemark 这个参数还蛮重要的,它的意思是在执行CMS remark之前进行一次youngGC,这样能有效降低remark的时间,之前我没有加这个参数,remark时间最大能达到3s,加上这个参数之后remark时间减少到1s之内。

-XX:+CMSParallelRemarkEnabled

2803.125: [GC 2803.125: [ParNew: 408832K->0K(409216K), 0.5371950 secs] 611130K->206985K(1048192K) icms_dc=4 , 0.5373720 secs]

2824.209: [GC 2824.209: [ParNew: 408832K->0K(409216K), 0.6755540 secs] 615806K->211897K(1048192K) icms_dc=4 , 0.6757740 secs]

Here, the scavenges took respectively 537 ms and 675 ms. In between these two scavenges, iCMS ran for a brief period as indicated by the icms_dc value, which indicates a duty-cycle. In this case the duty cycle was 4%. A simple calculation shows that the iCMS incremental step lasted for 4/100 \* (2824.209 - 2803.125 - 0.537) = 821 ms, i.e. 4% of the time between the two scavenges.

Starting with 1.5, CMS has one more phase – concurrent abortable preclean. Abortable preclean is run between a 'concurrent preclean' and 'remark' until we have the desired occupancy in eden. This phase is added to help schedule the 'remark' phase so as to avoid back-to-back pauses for a scavenge closely followed by a CMS remark pause. In order to maximally separate a scavenge from a CMS remark pause, we attempt to schedule the CMS remark pause roughly mid-way between scavenges.

There is a second reason why we do this. Immediately following a scavenge there are likely a large number of grey objects that need rescanning. The abortable preclean phase tries to deal with such newly grey objects thus reducing a subsequent CMS remark pause.

The scheduling of 'remark' phase can be controlled by two jvm options 

CMSScheduleRemarkEdenSizeThreshold and CMSScheduleRemarkEdenPenetration. The defaults for these are 2m and 50% respectively. The first parameter determines the Eden size below which no attempt is made to schedule the CMS remark pause because the pay off is expected to be minuscule. The second parameter indicates the Eden occupancy at which a CMS remark is attempted. 

After 'concurrent preclean' if the Eden occupancy is above CMSScheduleRemarkEdenSizeThreshold, we start 'concurrent abortable preclean' and continue precleanig until we have CMSScheduleRemarkEdenPenetration percentage occupancy in eden, otherwise we schedule 'remark' phase immediately.

7688.150: [CMS-concurrent-preclean-start]

7688.186: [CMS-concurrent-preclean: 0.034/0.035 secs]

7688.186: [CMS-concurrent-abortable-preclean-start]

7688.465: [GC 7688.465: [ParNew: 1040940K->1464K(1044544K), 0.0165840 secs] 1343593K->304365K(2093120K), 0.0167509 secs]

7690.093: [CMS-concurrent-abortable-preclean: 1.012/1.907 secs]

7690.095: [GC[YG occupancy: 522484 K (1044544 K)]7690.095: [Rescan (parallel) , 0.3665541 secs]7690.462: [weak refs processing, 0.0003850 secs] [1 CMS-remark: 302901K(1048576K)] 825385K(2093120K), 0.3670690 secs]

In the above log, after a preclean, 'abortable preclean' starts. After the young generation collection, the young gen occupancy drops down from 1040940K to 1464K. When young gen occupancy reaches 522484K which is 50% of the total capacity, precleaning is aborted and 'remark' phase is started. 

Note that in 1.5, young generation occupancy also gets printed in the final remark phase.

40.146: [GC [1 CMS-initial-mark: 26386K(786432K)] 26404K(1048384K), 0.0074495 secs]

40.154: [CMS-concurrent-mark-start]

40.683: [CMS-concurrent-mark: 0.521/0.529 secs]

40.683: [CMS-concurrent-preclean-start]

40.701: [CMS-concurrent-preclean: 0.017/0.018 secs]

40.704: [GC40.704: [Rescan (parallel) , 0.1790103 secs]40.883: [weak refs processing, 0.0100966 secs] [1 CMS-remark: 26386K(786432K)] 52644K(1048384K), 0.1897792 secs]

40.894: [CMS-concurrent-sweep-start]

41.020: [CMS-concurrent-sweep: 0.126/0.126 secs]

41.020: [CMS-concurrent-reset-start]

41.147: [CMS-concurrent-reset: 0.127/0.127 secs]

197.976: [GC 197.976: [ParNew: 260872K->260872K(261952K), 0.0000688 secs]197.976: [CMS197.981: [CMS-concurrent-sweep: 0.516/0.531 secs]

(concurrent mode failure): 402978K->248977K(786432K), 2.3728734 secs] 663850K->248977K(1048384K), 2.3733725 secs]

(concurrent mode failure):

To get the same functionality with UseSerialGC you need to explicitly specify the switch -XX:+HandlePromotionFailure.

这种情况:The concurrent mode failure can either be avoided by increasing the tenured generation size or initiating the CMS collection at a lesser heap occupancy by setting CMSInitiatingOccupancyFraction to a lower value and setting UseCMSInitiatingOccupancyOnly to true. 

283.736: [Full GC 283.736: [ParNew: 261599K->261599K(261952K), 0.0000615 secs] 826554K->826554K(1048384K), 0.0003259 secs]

GC locker: Trying a full collection because scavenge failed

283.736: [Full GC 283.736: [ParNew: 261599K->261599K(261952K), 0.0000288 secs]

Stop-the-world GC happening when a JNI Critical section is released. Here again the young generation collection failed due to “full promotion guarantee failure” and then the Full GC is being invoked.

CMS can also be run in incremental mode (i-cms), enabled with -XX:+CMSIncrementalMode. In this mode, CMS collector does not hold the processor for the entire long concurrent phases but periodically stops them and yields the processor back to other threads in application. It divides the work to be done in concurrent phases in small chunks(called duty cycle) and schedules them between minor collections. This is very useful for applications that need low pause times and are run on machines with small number of processors.

G1参数:

http://hllvm.group.iteye.com/group/topic/44381#post-272188

http://hllvm.group.iteye.com/group/topic/44529

https://www.zhihu.com/question/37028283

使用参数-XX:+UnlockExperimentalVMOptions –XX:+UseG1GC 来启用 G1 回收器

-XX:MaxGCPauseMills=20 -XX:GCPauseIntervalMills=200 :设置 G1 回收器的目标停顿时间

其他:

-XX:+UseSerialGC:在新生代和老年代使用串行回收器。(无用)

-XX:+SurvivorRatio:设置 eden 区大小和 survivor 区大小的比例。

-XX:+PretenureSizeThreshold:设置大对象直接进入老年代的阈值。当对象的大小超过这个值时,将直接在老年代分配。

-XX:MaxTenuringThreshold:设置对象进入老年代的年龄的最大值。每一次 Minor GC 后,对象年龄就加 1。任何大于这个年龄的对象,一定会进入老年代。

-XX:+DisableExplicitGC: 禁用显示 GC。

-XX:+TieredCompilation -XX:CICompilerCount=4

在开启多层编译,即-XX:+TieredCompilation,代码首先运行在解释模式,达到C1阈值2000之后,触发C1编译,达到C2阈值15000后,触发C2编译。

后台的编译线程数 由flag -XX:CICompilerCount 来决定

可以使用 -XX:+PrintFlagsFinal 来观察jvm运行时的具体参数值是多少

另外一个涉及线程数目运算的标识符是CICompilerCountPerCPU,逻辑是当CICompilerCountPerCPU == true时,_compiler_count = max(log2(8)-1,1)。

2. 与并行 GC 相关的参数

-XX:+UseParNewGC: 表示新生代使用并行收集器,老年代使用串行收集器

-XX:+UseParallelGC 参数设置,表示新生代和老年代均使用并行回收收集器

-XX:+UseParallelOldGC: 老年代使用并行回收收集器。

-XX:ParallelGCThreads:设置用于垃圾回收的线程数。通常情况下可以和 CPU 数量相等。但在 CPU 数量比较多的情况下,设置相对较小的数值也是合理的。

-XX:MaxGCPauseMills:设置最大垃圾收集停顿时间。它的值是一个大于 0 的整数。收集器在工作时,会调整 Java 堆大小或者其他一些参数,尽可能地把停顿时间控制在 MaxGCPauseMills 以内。

-XX:GCTimeRatio:设置吞吐量大小,它的值是一个 0-100 之间的整数。假设 GCTimeRatio 的值为 n,那么系统将花费不超过 1/(1+n) 的时间用于垃圾收集。

-XX:+UseAdaptiveSizePolicy:打开自适应 GC 策略。在这种模式下,新生代的大小,eden 和 survivor 的比例、晋升老年代的对象年龄等参数会被自动调整,以达到在堆大小、吞吐量和停顿时间之间的平衡点。

可以发现通过设置一个较大的年轻代预留新对象,设置合理的 Survivor 区并且提供 Survivor 区的使用率,可以将年轻对象保存在年轻代。一般来说,Survivor 区的空间不够,或者占用量达到 50%时,就会使对象进入年老代 (不管它的年龄有多大)。清单 4 创建了 3 个对象,分别分配一定的内存空间。

我们可以尝试加上-XX:TargetSurvivorRatio=90 参数

一个计算期望存活大小Desired survivor size的参数.
计算公式: (survivor_capacity * TargetSurvivorRatio) / 100 * sizeof(a pointer):survivor_capacity(一个survivor space的大小)乘以TargetSurvivorRatio,
                         表明所有age的survivor space对象的大小如果超过Desired survivor size,则重新计算threshold,以age和MaxTenuringThreshold的最小值为准,否则以MaxTenuringThreshold为准.

JDK1.8持久代被元空间替代

使用-XX:MetaSpaceSize-XX:MaxMetaspaceSize代替原来的-XX:PermSize-XX:MaxPermSize

-XX:MaxMetaspaceSize=128m

查看jvm的默认参数

java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version 

#JVM_GC=$JVM_GC" -XX:ParallelGCThreads=4 -XX:InitiatingHeapOccupancyPercent=45  -XX:MaxGCPauseMillis=40  -XX:ConcGCThreads=1 -XX:G1ReservePercent=10"

如果你的Java应用已经是运行状态了,你想查看某个JVM参数生效没有可以使用jinfo这个工具。比如说大名鼎鼎的G1垃圾回收器,在JDK7update3中不论是客户端(-client)还是服务器(-server)模式下都不是默认启动的。

    jinfo是随JDK一起发布的,使用时先用jps找到Java应用的pid。直接运行jinfo可以查看使用说明。

jinfo -flag UseParallelOldGC 31072  

JDK8 里-XX:MaxTenuringThreshold 的最大值是15

用jmeter对服务进行压测,一个需要吞吐量的应用,2000个线程,JVM参数如下

-XX:LargePageSizeInBytes=128m 内存页的大小, 不可设置过大, 会影响Perm的大小。 

-XX:+UseFastAccessorMethods 原始类型的快速优化

另外 -Xss 是线程栈的大小, 这个参数需要严格的测试, 一般小的应用, 如果栈不是很深, 应该是128k够用的, 不过,我们的应用调用深度比较大, 还需要做详细的测试。 这个选项对性能的影响比较大。 建议使用256K的大小.

-XX:+AggressiveOpts 加快编译

-XX:+UseBiasedLocking 锁机制的性能改善。

-XX:+PrintSafepointStatistics -XX:+PrintGCApplicationStoppedTime -XX:PrintSafepointStatisticsCount=1

-XX:CMSFullGCsBeforeCompaction=5 

-XX:+CMSScavengeBeforeRemark -XX:+DisableExplicitGC -XX:ErrorFile=/opt/logs/mobile/sieve-service/.vmerr.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/logs/mobile/sieve-service/.heaperr.log -XX:InitialCodeCacheSize=134217728 -XX:InitialHeapSize=11811160064 -XX:MaxHeapSize=11811160064 -XX:MaxNewSize=5368709120 -XX:MaxPermSize=268435456 -XX:NewRatio=2 -XX:NewSize=5368709120 -XX:OldPLABSize=16 -XX:PermSize=268435456 -XX:+PrintGC -XX:+PrintGCCause -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1 -XX:+PrintTenuringDistribution -XX:ReservedCodeCacheSize=134217728 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8 -XX:+UseCMSCompactAtFullCollection -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+UseParNewGC 

二、查看设置JVM内存信息

Runtime.getRuntime().maxMemory(); //最大可用内存,对应-Xmx

Runtime.getRuntime().freeMemory(); //当前JVM空闲内存

Runtime.getRuntime().totalMemory(); //当前JVM占用的内存总数,其值相当于当前JVM已使用的内存及freeMemory()的总和

关于maxMemory(),freeMemory()和totalMemory():

maxMemory()为JVM的最大可用内存,可通过-Xmx设置,默认值为物理内存的1/4,设值不能高于计算机物理内存;

totalMemory()为当前JVM占用的内存总数,其值相当于当前JVM已使用的内存及freeMemory()的总和,会随着JVM使用内存的增加而增加;

freeMemory()为当前JVM空闲内存,因为JVM只有在需要内存时才占用物理内存使用,所以freeMemory()的值一般情况下都很小,而 JVM实际可用内存并不等于freeMemory(),而应该等于maxMemory()-totalMemory()+freeMemory()。及其 设置JVM内存分配。

上面表格中黑体的三个参数代表着jvm中GC执行的三种方式,即串行、并行、并发;

串行(SerialGC)是jvm的默认GC方式,一般适用于小型应用和单处理器,算法比较简单,GC效率也较高,但可能会给应用带来停顿;

并行(ParallelGC)是指GC运行时,对应用程序运行没有影响,GC和app两者的线程在并发执行,这样可以最大限度不影响app的运行;

并发(ConcMarkSweepGC)是指多个线程并发执行GC,一般适用于多处理器系统中,可以提高GC的效率,但算法复杂,系统消耗较大;

-XX:+ScavengeBeforeFullGC 新生代GC优先于Full GC执行

-XX:+UseGCOverheadLimit 在抛出OOM之前限制jvm耗费在GC上的时间比例

-XX:+UseThreadPriorities 启用本地线程优先级

-XX:ReservedCodeCacheSize=32m 保留代码占用的内存容量

-XX:ThreadStackSize=512 设置线程栈大小,若为0则使用系统默认值

-XX:+UseLargePages 使用大页面内存

-XX:LargePageSizeInBytes=4m 设置用于Java堆的大页面尺寸

-XX:MaxHeapFreeRatio=70 GC后java堆中空闲量占的最大比例

-XX:MaxNewSize=size 新生成对象能占用内存的最大值

-XX:MaxPermSize=64m 老生代对象能占用内存的最大值

-XX:MinHeapFreeRatio=40 GC后java堆中空闲量占的最小比例

-XX:NewRatio=2 新生代内存容量与老生代内存容量的比例

-XX:NewSize=2.125m 新生代对象生成时占用内存的默认值

日志类:

参数及其默认值 描述

-XX:-CITime 打印消耗在JIT编译的时间

-XX:ErrorFile=./hs_err_pid<pid>.log 保存错误日志或者数据到文件中

-XX:-ExtendedDTraceProbes 开启solaris特有的dtrace探针

-XX:HeapDumpPath=./java_pid<pid>.hprof 指定导出堆信息时的路径或文件名

-XX:-HeapDumpOnOutOfMemoryError 当首次遭遇OOM时导出此时堆中相关信息

-XX: 出现致命ERROR之后运行自定义命令

-XX:OnOutOfMemoryError="<cmd args>;<cmd args>" 当首次遭遇OOM时执行自定义命令

-XX:-PrintClassHistogram 遇到Ctrl-Break后打印类实例的柱状信息,与jmap -histo功能相同

-XX:-PrintConcurrentLocks 遇到Ctrl-Break后打印并发锁的相关信息,与jstack -l功能相同

-XX:-PrintCommandLineFlags 打印在命令行中出现过的标记

-XX:-PrintCompilation 当一个方法被编译时打印相关信息

-XX:-PrintGC 每次GC时打印相关信息

-XX:-PrintGCDetails 每次GC时打印详细信息

-XX:-PrintGCTimeStamps 打印每次GC的时间戳

-XX:-TraceClassLoading 跟踪类的加载信息

-XX:-TraceClassLoadingPreorder 跟踪被引用到的所有类的加载信息

-XX:-TraceClassResolution 跟踪常量池

-XX:-TraceClassUnloading 跟踪类的卸载信息

-XX:-TraceLoaderConstraints 跟踪类加载器约束的相关信息

查询前10的文件夹大小

du -a /var | sort -n -r | head -n 10

1 Critical 禁用了显式GC,存在堆外内存OOM的风险,请在启动参数中移除 -XX:+DisableExplicitGC 参数 2018-11-21 17:12:16 scalpel

2 Major 启动时添加 -XX:+PrintFlagsFinal 参数,可以在 JVM 启动时输出所有参数值,便于检查参数是否被覆盖 2018-11-21 17:12:16 scalpel

3 Minor 如果服务存在明显的锁竞争,请使用 -XX:-UseBiasedLocking 参数取消偏向锁 2018-11-21 17:12:16 scalpel

4 Minor 在日志中输出 STW 的暂停时间,可定位其他 STW 操作,启动参数中添加 -XX:+PrintGCApplicationStoppedTime 开启

#!/usr/bin/env bash

## jvm init options

JVM_OPTS="$JVM_OPTS -server"

JVM_OPTS="$JVM_OPTS -Dfile.encoding=UTF-8"

JVM_OPTS="$JVM_OPTS -Dsun.jnu.encoding=UTF-8"

JVM_OPTS="$JVM_OPTS -Djava.io.tmpdir=/tmp"

JVM_OPTS="$JVM_OPTS -Djava.net.preferIPv6Addresses=false"

## jvm gc strategy options

# Use the Hotspot garbage-first collector.

JVM_OPTS="$JVM_OPTS -XX:+UseG1GC"

# Main G1GC tunable: lowering the pause target will lower throughput and vise versa.

# 200ms is the JVM default and lowest viable setting

JVM_OPTS="$JVM_OPTS -XX:MaxGCPauseMillis=60"

## jvm memory options

# With G1 the Java heap is subdivided into uniformly sized regions. This sets the size of the individual sub-divisions.

# The default value of this parameter is determined ergonomically based upon heap size.

# The minimum value is 1Mb and the maximum value is 32Mb. Introduced in Java 6 Update 26.

JVM_OPTS="$JVM_OPTS -XX:G1HeapRegionSize=4m"

# Max heap size

JVM_OPTS="$JVM_OPTS -Xmx4608m"

# Min heap size

JVM_OPTS="$JVM_OPTS -Xms4608m"

# Stack size

JVM_OPTS="$JVM_OPTS -Xss512k"

# Ratio of old/eden space size

JVM_OPTS="$JVM_OPTS -XX:NewRatio=1"

# Ratio of eden/survivor space size

JVM_OPTS="$JVM_OPTS -XX:SurvivorRatio=8"

# Metaspace size

JVM_OPTS="$JVM_OPTS -XX:MetaspaceSize=128m"

# Max metaspace size

JVM_OPTS="$JVM_OPTS -XX:MaxMetaspaceSize=256m"

# Initial code cache size

JVM_OPTS="$JVM_OPTS -XX:InitialCodeCacheSize=128m"

# Reserved code cache size - maximum code cache size

JVM_OPTS="$JVM_OPTS -XX:ReservedCodeCacheSize=256m"

# Start GC later to increase throughput.

# The default in Hotspot 8u40 is 40%.

JVM_OPTS="$JVM_OPTS -XX:InitiatingHeapOccupancyPercent=45"

# Enables object-reference compression capabilities via the Compressed References.

JVM_OPTS="$JVM_OPTS -XX:+UseCompressedOops"

# Enables big integer cache

JVM_OPTS="$JVM_OPTS -XX:AutoBoxCacheMax=60000"

## jvm monitor logging options

JVM_OPTS="$JVM_OPTS -XX:-OmitStackTraceInFastThrow"

# generate a heap dump when an allocation from the Java heap fails

# heap dumps are created in the working directory of the JVM

# may have a pernicious effect for other services whic

加些参数,来看看具体在那段耗时时间比较长,-XX:+PrintReferenceGC -XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1 -XX:+PrintGCApplicationStoppedTime

JDK7之前单线程,JDK8之后并行,可以通过参数CMSParallelInitialMarkEnabled调整

  • 增多回收线程的个数 CMS默认的垃圾收集线程数是(CPU个数 + 3/4,这个公式的含义是:当CPU个数大于4个的时候,垃圾回收后台线程至少占用25%的CPU资源。举个例子:如果CPU核数是1~4个,那么会有1个CPU用于垃圾收集,如果CPU核数是5~8个,那么久会有2个CPU用于垃圾收集。

1.(STW)初始标记:这个阶段是标记从GcRoots直接可达的老年代对象、新生代引用的老年代对象,就是下图中灰色的点。这个过程是单线程的(JDK7之前单线程,JDK8之后并行,可以通过参数CMSParallelInitialMarkEnabled调整)。

2. 并发标记:由上一个阶段标记过的对象,开始tracing过程,标记所有可达的对象,这个阶段垃圾回收线程和应用线程同时运行,如上图中的灰色的点。在并发标记过程中,应用线程还在跑,因此会导致有些对象会从新生代晋升到老年代、有些老年代的对象引用会被改变、有些对象会直接分配到老年代,这些受到影响的老年代对象所在的card会被标记为dirty,用于重新标记阶段扫描。这个阶段过程中,老年代对象的card被标记为dirty的可能原因,就是下图中绿色的线:

3. 预清理:预清理,也是用于标记老年代存活的对象,目的是为了让重新标记阶段的STW尽可能短。这个阶段的目标是在并发标记阶段被应用线程影响到的老年代对象,包括:(1)老年代中card为dirty的对象;(2)幸存区(from和to)中引用的老年代对象。因此,这个阶段也需要扫描新生代+老年代。【PS:会不会扫描Eden区的对象,我看源代码猜测是没有,还需要继续求证】

4. 可中断的预清理:这个阶段的目标跟“预清理”阶段相同,也是为了减轻重新标记阶段的工作量。可中断预清理的价值:在进入重新标记阶段之前尽量等到一个Minor GC,尽量缩短重新标记阶段的停顿时间。另外可中断预清理会在Eden达到50%的时候开始,这时候离下一次minor gc还有半程的时间,这个还有另一个意义,即避免短时间内连着的两个停顿,如下图资料所示:

在预清理步骤后,如果满足下面两个条件,就不会开启可中断的预清理,直接进入重新标记阶段:

  • Eden的使用空间大于“CMSScheduleRemarkEdenSizeThreshold”,这个参数的默认值是2M;
  • Eden的使用率大于等于“CMSScheduleRemarkEdenPenetration”,这个参数的默认值是50%。

如果不满足上面两个条件,则进入可中断的预清理,可中断预清理可能会执行多次,那么退出这个阶段的出口有两个(源码参见下图): – 设置了CMSMaxAbortablePrecleanLoops,并且执行的次数超过了这个值,这个参数的默认值是0; – CMSMaxAbortablePrecleanTime,执行可中断预清理的时间超过了这个值,这个参数的默认值是5000毫秒。

cms : abort preclean 

有可能可中断预清理过程中一直没等到Minor gc,这时候进入重新标记阶段的话,新生代还有很多活着的对象,就回导致STW变长,因此CMS还提供了CMSScavengeBeforeRemark参数,可以在进入重新标记之前强制进行依次Minor gc。

  1. 针对永久代的调优 如果永久代需要垃圾回收(或元空间扩容),就会触发Full GC。默认情况下,CMS不会处理永久代中的垃圾,可以通过开启CMSPermGenSweepingEnabled配置来开启永久代中的垃圾回收,开启后会有一组后台线程针对永久代做收集,需要注意的是,触发永久代进行垃圾收集的指标跟触发老年代进行垃圾收集的指标是独立的,老年代的阈值可以通过CMSInitiatingPermOccupancyFraction参数设置,这个参数的默认值是80%。开启对永久代的垃圾收集只是其中的一步,还需要开启另一个参数——CMSClassUnloadingEnabled,使得在垃圾收集的时候可以卸载不用的类。

4 ExplicitGCInvokesConcurrentAndUnloadsClasses 将System.gc()触发的Full GC转换为一次CMS并发收集,并且在这个收集周期中卸载 Perm(Metaspace)区域中不需要的类

5 CMSClassUnloadingEnabled 在CMS收集周期中,是否卸载类

猜你喜欢

转载自blog.csdn.net/chenpeng19910926/article/details/86500716