JVM中垃圾回收GC生产参数,GC选择+工作线程+内存设置相关参数

JVM中垃圾回收相关参数介绍

用好JVM的垃圾回收功能有两个关键点:一是需要理解GC算法的原理和实现,二是需要知道JVM到底提供了哪些参数,这些参数用于控制什么。

然而实际工作更为困难,一方面是要理解参数,需要理解实现细节;另一方面,JDK不断升级变化,在升级的过程中GC的实现也会发生变化,参数会增加或删除,某些版本中甚至存在一些错误的实现,从而导致参数的含义发生了变化。长期以来,官方提供的参数说明文档是程序员唯一可以信赖的理解参数作用的文档。但是官方提供的文档非常简单,通常只有一句简单的描述,根本不足以满足调参的需要。这一部分着重介绍JVM提供的参数。

要想用好参数,首先需要理解参数的作用。目前生产环境中使用最为广泛的是GC还是分代垃圾回收器,不同GC的实现不同,提供的参数也不同。下面以G1为例演示GC调优的一般思路。首先来看看分代对应用的影响,如下图所示。

根据图中介绍,新生代大小会影响停顿时间,Survival的大小,即Form和To空间会影响Minor GC的回收性能,Eden的大小会影响Mutator的分配,即执行效率,老生代的大小会影响GC执行性能、停顿时间、内存可用空间等,Full GC影响停顿时间。

在GC调优时,应根据应用运行的特点调整相关参数,从而保证应用运行效率高、GC停顿时间短。就G1来说,可以从以下几方面调整参数。

1)堆空间:最大堆和最小堆、目标停顿时间设置、分区大小。

2)新生代:TLAB大小、YoungPLAB大小、ResizeTLAB设置、ResizePLAB设置、SurvivalAge设置。

3)老生代:并发标记触发时机、OldPLAB大小,混合回收时老生代参与回收的限制。

4)硬件特性适配:NUMA-Aware、NV-DIMM。

5)代际管理:存储粒度、并发处理和Minor GC的交互。

6)Minor GC、Mixed GC、Full GC并行的线程数目,以及并行任务均衡和终止机制。

7)引用集处理并发的线程数目。

8)并发标记的线程数目。

9)Java语言中引用回收方式和执行方式。

10)GC过程异常情况的处理:晋升失败、保留内存等。

由此可以看出,GC调优不仅需要掌握相关理论的知识,还需要掌握实现的细节及控制细节的参数。本节将详细介绍各种GC相关的参数。

由于不同的JDK版本参数有所变化,大家通常使用的是LTS版本的JDK,所以本书仅对JDK 8、JDK 11和JDK 17的参数做总结和梳理。

实现中提供了不同类型的参数,比如生产参数、实验参数、诊断参数、可动态调整的参数、验证参数、开发参数等,不同的参数类型主要是告诉使用者参数的作用。

1)生产参数:参数说明中包含product,生产参数表示参数已经非常稳定,经过了长期的验证,可以用在生产环境中。

2)实验参数:使用实验参数时需要添加-XX:+
UnlockExperimentalVMOptions才能开启。这些参数并未经历过大规模的使用,可能存在一定的性能、稳定性风险。通常这些参数配合一些新开发的特性来使用。

3)诊断参数:在诊断JVM系统的内部行为时使用,使用时需要添加-XX:+
Un-lockDiagnosticVMOptions才能开启。该类参数通常会暴露更多的运行时信息,以便使用者理解系统。诊断参数通常会影响性能,所以一般不会直接用在生产环境中,通常用于问题定位。

4)可动态调整的参数:JVM的很多参数在启动后就确定下来,但是还有一些参数可以在系统运行的过程中通过API动态地修改,以便控制或者改变JVM内部运行的机制。

5)验证参数:JVM还提供了一些以Verify开发的系列参数,这类参数通常用于验证JVM的运行状态是否符合运行的预期,是JVM开发和测试非常有用的助手。

6)开发参数:开发参数在普通的Release版本中并不存在,仅仅适用于调试版本。这类参数通常能给JVM开发者提供详细的信息,以便开发者理解JVM运行是否符合预期。

GC通用参数

Hotspot中实现了6种垃圾回收器(GC),虽然每种在实现时都有所不同,但是它们还是有一些共同的地方,例如都需要设置堆大小、TLAB、并行/并发线程数等。本章介绍这些通用参数,其中部分参数适用于所有GC,部分参数适用于某几个GC,少数参数只适用于某一个GC。

GC生产参数

GC选择相关参数

Hotspot提供了6种GC,但只能选择一种使用。每种GC使用一个参数进行控制,满足不同场景的诉求。

该参数使用串行垃圾回收器进行垃圾回收。参数的默认值为false,表示JVM启动后并不使用串行回收。

参数UseParallelGC表示使用并行复制回收新生代,参数UseParallelOldGC表示使用并行标记压缩回收整个堆空间。

当参数UseParallelGC设置为true时,参数UseParallelOldGC也默认设置为true。如果参数UseParallelGC设置为true,UseParallelOldGC设置为false,则使用并行复制回收新生代,使用串行标记压缩算法对整个内存进行垃圾回收。

在JDK 9之前,并行垃圾回收器是默认的垃圾回收器,即参数UseParallelGC默认为true,从JDK 9开始该参数默认为false。

参数UseParallelOldGC在JDK 17中被删除,当设置UseParallelGC为true时,默认使用并行标记压缩回收整个堆空间(相当于只允许UseParallelOldGC为true)。删除参数的原因是并行新生代回收和串行标记压缩配合没有任何实际意义,不应该存在这样的配置。

该参数表示使用CMS进行垃圾回收。该参数默认使用ParNew回收新生代,使用并发标记清除回收老生代,使用串行标记压缩回收整个堆空间。参数的默认值为false,表示不使用CMS进行垃圾回收。

该参数表示使用Shenandoah GC进行垃圾回收。参数的默认值为false,表示不使用Shenandoah进行垃圾回收。

JVM内部会根据机器的性能来推断使用哪种GC进行垃圾回收。GC选择的逻辑如下:

1)参数
NeverActAsServerClassMachine为true,使用Serial回收。

2)参数
NeverActAsServerClassMachine为false、参数NeverActAsServerClassMachine和AlwaysActAsServerClassMachine同时为true,优先使用G1,当G1不可用时(指的是没有编译配置G1)选择ParallelGC,Parallel GC不可用时(没有编译配置Parallel GC)选择Serial回收。

3)参数
NeverActAsServerClassMachine为true,且参数AlwaysActAsServerClassMachine为false,根据硬件信息确认使用哪种模式,判断逻辑为:如果CPU核数大于2个并且内存大于2GB,则优先使用G1,当G1不可用时选择Parallel GC,Parallel GC不可用时选择Serial回收,否则直接使用Serial回收。

另外值得一提的是,参数
NeverActAsServerClassMachine的值还与使用的编译优化模式相关,如果只开启了C1,则参数NeverActAsServerClassMachine为true,如果开启了C2,则参数NeverActAsServerClassMachine为false。

参数
NeverActAsServerClassMachine的默认值与平台相关,在X86平台上C1编译器的默认值为true、C2编译器的默认值为false,参数AlwaysActAsServerClassMachine的默认值为false。

提供两个参数的原因是不同的平台上OS获得的硬件信息会有差别,这可能导致不同平台上JVM的行为不一致,如果发现这样的情况,且需要保证多平台行为的一致性,可以直接通过这两个参数控制。

GC工作线程相关参数

除了串行回收,Parallel GC、CMS、G1、ZGC和Shenandoah中涉及多个线程并行或者并发工作,线程个数可以通过参数控制,本节介绍相关参数。

该参数用于设置并行GC工作线程的数目,参数的默认值为0。如果参数没有设置(即保持默认值),JVM根据机器硬件计算得到并行工作线程数。不同的GC计算略有不同,如下:

对于Parallel GC/CMS/G1/Shenandoah,计算公式如下:

对于ZGC,计算公式如下:

ParallelGCThreads = ncpus×60%

其中ncpus为CPU的核数。

根据CPU个数计算并行线程数的目的是防止在一些高性能计算机上CPU核数非常多,比如可以达到128个,如果不对并行线程数做限制,并行工作线程会非常多,可能会导致应用性能下降。性能下降的主要原因是在并行工作时多线程可能会发生任务均衡,同时多个线程需要同步达到终止状态,当并行线程过多时,可能会因为任务窃取效率低下及大量线程同步而出现整体性能下降。

该参数用于设置并发GC工作线程的数目,参数的默认值为0。JVM内部要求ConcGC-Threads小于ParallelGCThreads,如果设置参数,必须为小于ParallelGCThreads的值;如果没有设置参数,JVM会根据不同的GC计算参数的值。计算方法如表9-1所示。

表9-1 不同GC计算参数ConcGCThreads的方法

该参数用于设置是否允许动态调整并行/并发GC工作线程的数目。对于不同的GC,该参数的作用范围不同。具体如下:

1)Parallel GC中可以调整并行工作线程数,影响Minor GC和Full GC。

2)G1中可以调整并发标记的线程数,也可以调整Refine线程数,还可以调整并行工作线程数。

3)CMS中可以调整并行工作线程数,但是不能调整并发线程数目。

4)Shenandoah中可以调整并行和并发工作线程数。

5)ZGC不受此参数控制,实现了额外的控制逻辑。

这是一种在允许GC工作线程动态调整的实现中(参数
UseDynamicNumberOfGCThreads为true时)智能推断GC线程个数的方法。

具体方法为:使用整个堆内存的大小除以参数HeapSizePerGCThread,得到线程的个数,假定用此种方式推测出GC工作线程个数为Number_Worker1。该方法的逻辑是,假设每个GC工作线程处理的内存大小为HeapSize-PerGCThread。

GC工作线程调整的另外一种智能推断GC线程个数的方法如下:将正在允许的Java线程个数的两倍作为一个上限,假定此种方式推测出GC工作线程的个数为Number_Worker2。

动态GC工作线程的预测值为Min(Max(Number_Worker1,Number_Worker2),ParallelGC- Threads)。

参数HeapSizePerGCThread在不同的平台中的默认值不同,在32位系统中的默认值为128MB,在64位系统中的默认值为128MB×1.3(注意1.3是一个平台系数)。

该参数表示GC线程在运行的时候可以记录线程运行的时间信息,使用一个数组记录这些数据,当数据输出之后,所有的数据将被清除。该参数只有在debug的日志下才会生效。参数的默认值为200,表示每间隔200毫秒记录一次信息。

由于JVM内部重构了参数动态调整的实现,因此该参数不再有效,在JDK14中被移除。

该参数用于指定ncpu的值。该值会影响并行/并发线程的个数。如果指定了该参数,JVM将不再使用运行环境中真实CPU的个数。参数的默认值为-1,表示不指定ncpu的值,由JVM通过系统API获得真实的CPU个数。

注意,运行环境可能是Docker容器,也可能是真实的物理机。

内存设置相关参数

Hotspot提供了参数用于控制堆空间大小、分代GC各个代的大小等。本节介绍相关参数。

该参数用于设置JVM最大可以使用的物理内存,适用于所有的垃圾回收器。该参数是平台相关的参数(例如在X86 32位系统中该值默认为1GB)。当没有设置最大堆空间时,使用该参数智能推断堆空间大小。如果参数没有设置,将使用操作系统API获取系统的物理内存,用于进行堆空间的计算。单位是B,可以兼容G/K/M等符号,如设置为4GB。

参数MaxHeapSize和Xmx用于设置JVM最大可用的堆空间,在32位系统中,参数的默认值为96MB。若没有设置参数MaxHeapSize,则会通过可用物理内存(记为physical_memory)来估算并修正默认值。修正的方式如下:

1)当physical_memory或者MaxRAM指定的可用物理空间小于系统参数默认值的2倍时(例如32位系统,物理空间小于96×2 = 192MB),

2)否则

参数MaxRAMPercentage和参数MinRAMPercentage的默认值分别是25和50,含义是MaxHeapSize理想空间是物理空间的25%,如果物理空间特别小,那么MaxHeapSize不少于物理空间的50%。

参数MaxRAMFraction和参数MaxRAMPercentage的作用类似,两者存在换算关系,如下:

参数MinRAMFraction和参数MinRAMPercentage的作用类似,两者存在换算关系,如下:

参数Xmx、MaxRAMFraction和MinRAMFraction在JDK 10之后被标记为丢弃,而仅使用MaxHeapSize、MaxRAMPercentage和MinRAMPercentage,原因是后者更为直观、便于理解。当然这两类参数目前都还有效,如果同时设置,那么只有后者生效。

该参数用于调整堆空间自动计算的边界值。当MaxHeapSize没有设置时,则JVM会自动计算参数MaxHeapSize,如果设置了参数ErgoHeapSizeLimit,那么JVM会取计算值和ErgoHeapSizeLimit两个之中较小的那个用于最终的计算中。

参数InitialHeapSize用于设置JVM启动后初始化的堆空间大小。如果初始化堆空间没有设置,则JVM会通过可用物理内存来估算InitialHeapSize,计算方式如下:

参数InitialRAMPercentage的默认值为1.526%(即1/64)。参数InitialRAMFraction和参数InitialRAMPercentage的作用类似,两者存在换算关系,如下:

参数InitialRAMFraction在JDK 10之后被标记为丢弃。

废弃InitialRAMFraction使用InitialRAMPercentage的原因是后者更为直观,便于理解。两个参数目前都还有效,如果两个参数同时设置,则只有参数InitialRAMPercentage生效。

参数MinHeapSize和Xms用于设置JVM启动后最小可用的堆空间大小。如果最小堆空间没有设置,则JVM会通过可用物理内存来估算最小堆空间。计算方式如下:

MinHeapSize = Min(InitialHeapSize, OldSize + NewSize)其中OldSize和NewSizie也是来自参数值。

这两个参数用于设置分代垃圾回收器新生代的大小,NewSize的默认值在32位系统中为1MB。如果没有设置NewSize,那么JVM会通过InitialHeapSize来估算NewSize。计算方式如下:

该参数用于设置分代垃圾回收器新生代的最大值(新生代最多可用的空间大小)。如果MaxNewSize没有设置,则MaxNewSize的计算方式如下:

该参数用于设置分代垃圾回收器老生代的大小,OldSize的默认值在32位系统中为4MB。如果没有设置老生代大小,则JVM会通过MaxHeapSize来估算OldSize。计算方式如下:

该参数根据比例设置新生代大小,默认值为2。如果没有设置MaxNewSize和NewSize,可以使用NewRatio计算MaxNewSize和NewSize;如果设置了MaxNewSize和NewSize,则直接丢弃参数NewRatio。

在分代垃圾回收器中,新生代采用复制算法,复制算法中有一个Eden和两个Survivor分区,该参数用于计算Survivor的大小,公式为

参数的默认值为8,表示Survivor分区占整个新生代大小的1/10。

在Parallel GC中,该参数不直接影响Survivor分区的大小,而是通过MinSurvivorRatio和InitialSurvivorRatio设置Survivor分区大小。而G1/ZGC/Shenandoah是分区设置,不需要该参数控制。

在64位系统中,若设置了UseCompressedOops,则Java的堆从地址HeapBaseMinAddress开始,参数的默认值是2GB。

压缩指针仅适用于堆空间小于32GB的情况。在JVM内部的很多地方使用malloc进行内存分配,这些分配的内存都将在HeapBaseMinAddress之下。所以在实际应用中如果遇到本地堆栈的溢出,则可以调整该参数值,避免本地堆和Java堆的冲突。

该参数用于动态调整新生代和老生代的大小,参数的默认值为true。仅适用于Parallel GC,在CMS中即使将该参数设置为true,也会重新定义为false。

在垃圾回收(包含Minor GC或者Full GC)执行的最后,可以根据统计的历史数据来动态地调整各个空间的大小。

当设置参数UseAdaptiveSizePolicy后,会在暂停时间和吞吐量之间取得一个平衡,然后调整新生代和老生代大小。停顿时间和吞吐量的平衡点在于:

1)一个合适的最大GC停顿时间。

2)一个合适的最大Minor GC停顿时间。

3)一个合适的应用程序吞吐量。

4)一个合适的额外内存空间占用。

注意

在调整内存大小时,上述4种方法是有优先级的。停顿时间优先级最高,其次是吞吐量,最后是额外空间占用的情况。只有前面的调整策略不满足的情况下才会使用后面的调整策略。策略如下:

1)如果GC停顿时间大于目标暂停时间(通过参数设置,-XX:MaxGCPauseMillis =nnn)或者Minor GC停顿时间大于目标暂停时间(-XX:MaxGCMinorPauseMillis = nnn),则降低新生代大小以匹配目标暂停时间。

2)否则,如果暂停时间合适,则考虑应用的吞吐量,通过增大新生代的大小满足吞吐量。

3)否则,如果允许调整JVM本地内存使用,则增加新生代的大小,减少Full GC的次数。

在调整过程中使用4个参数,分别如下:

-XX:MaxGCPauseMillis=nnn:不能设置得过小,否则会阻碍吞吐量。如果不设置,那么不使用停顿时间调整新生代、老生代大小。

-XX:MaxGCMinorPauseMillis=nnn:不能设置得过小,否则会阻碍吞吐量。如果不设置,那么不使用停顿时间调整新生代大小。

-XX:GCTimeRatio=nnn:用在垃圾回收上的时间不超过应用运行时间的

。参数的默认值为99,表示垃圾回收时间不应该超过整体时间的1%。


UseAdaptiveSizePolicyFootprintGoal:是否允许调整新生代和老生代的划分比例,以减少JVM本地内存消耗,默认值为true。

该参数允许调整新生代和老生代的大小以减少JVM本地内存的消耗。默认值为true,表示允许调整新生代和老生代的大小。

该参数允许在Minor GC执行结束后动态地计算新生代、老生代的大小划分,仅适用于Parallel GC。该参数需要在参数UseAdaptiveSizePolicy为true时才有效。参数的默认值为true,表示在执行Minor GC后调整新生代、老生代的大小划分。

该参数允许在Full GC执行结束后动态地计算新生代、老生代的大小划分,仅适用于Parallel GC。该参数需要在参数UseAdaptiveSizePolicy为true时才有效。参数的默认值为true,表示在执行Full GC后调整新生代、老生代的大小划分。

执行允许在调用System.gc的GC后动态地计算新生代、老生代的大小的划分(包含Minor GC和Full GC,Minor GC仅用于Full GC触发后,在执行过程中执行一次额外的Minor GC才符合条件,一般的Minor GC不满足该条件。参数ScavenageBeforeFullGC为true,Parallel GC会在Full GC执行前执行一次Minor GC),仅适用于Parallel GC。该参数必须在参数UseAdaptiveSizePolicy为true时才有效。

以上参数是新生代、老生代的大小划分的控制方法之一,使用吞吐量作为目标来动态地调整(吞吐量由GCTimeRatio控制)新生代、老生代的大小划分。

参数
AdaptiveSizeThroughPutPolicy将根据吞吐量调整新生代或者老生代的大小,基本逻辑是:

新生代或者老生代空间变大,垃圾回收发生的概率变小,吞吐量将提高。该参数只会增加内存空间的大小,不会缩小内存空间的大小。当Mutator的吞吐量低于目标阈值时:

1)参数值设置为0时,直接增加的内存大小,且增加的大小通过一个简单公式调整计算。

2)参数值设置为1时,在执行Minor GC后调整新生代的大小。需要通过预测模型来估算新生代的吞吐量变化情况,如果预测吞吐量还会继续增加,则暂时不调整新生代内存的大小,否则通过一个简单的公式来调整大小;在执行Full GC后调整老生代的大小,需要通过预测模型来估算老生代的吞吐量变化情况,如果预测吞吐量还会继续增加,则暂时不调整老生代内存大小,否则通过一个简单公式来调整大小。由于预测模型可能会因为没有足够的历史数据而出现模型预测误差,因此在模型预测的情况下引入了一个额外的参数
AdaptiveSize-PolicyInitializingSteps,控制只有在收集一定次数的数据后才可以使用模型进行预测。

参数
AdaptiveSizeThroughPutPolicy的默认值为0,表示直接调整,无须考虑吞吐量变化的情况;参数AdaptiveSizePolicyInitializingSteps的默认值为20,表示只有经过20次内存增加后才会使用模型进行预测。

内存调整过程涉及两个部分:其一,通过公式调整内存的值,公式是什么;其二,预测模型预测吞吐量的变化,预测模型是什么。这两部分都涉及一些参数。下面结合参数分别看一看公式和预测模型及模型的使用。

Minor GC和Full GC后控制Eden增加。计算公式使用了3个参数:

Eden最后增加的大小为eden_scaled。

其中参数
YoungGenerationSizeIncremen的默认值为20,根据公式,Eden每次调整最少增加20%(记为基础增幅);参数YoungGenerationSizeSupplement的默认值为80,表示JVM运行早期Eden会额外增加80%(记为额外增幅),但是随着Minor GC执行次数的增加,这个值会逐渐变小,最后额外增幅会变成0。

参数
YoungGenerationSizeSupplementDec-ay的默认值为8,控制额外增幅衰减的粒度,表示每执行8次Minor GC,额外增幅减少一半,根据计算可以得到大概发生56次Minor GC后,额外增幅变为0。

在公式中用到了eden_desired、minor_gc_cost、full_gc_cost,它们是Parallel GC运行过程中Eden、Minor GC和Full GC的预测值。下面的参数会介绍它们具体的计算方法。

Full GC后控制老生代增加。计算公式使用了3个参数:

Old最后增加的大小为old_scaled。

其中参数
TenuredGenerationSizeIncrement的默认值为20,根据公式表示Old每次调整最少增加promoted_desired的20%(记为基础增幅);参数TenuredGenerationSizeSupplement的默认值为80,表示JVM运行早期Old会额外增加promoted_desired的80%(记为额外增幅),但是随着Full GC执行次数的增加,这个值会逐渐变小,最后额外增幅会变成0。参数TenuredGenerationSizeSupplementDecay的默认值为2,控制额外增幅衰减的粒度,表示每执行2次Full GC,额外增幅减少一半,根据计算可以得到大概发生14次Full GC后额外增幅变为0。

在公式中使用了promoted_desired、minor_gc_cost、full_gc_cost,它们是Parallel GC运行过程中promoted_desired(预期晋升内存大小)、Minor GC和Full GC相关的预测值,下面的参数会介绍它们具体的计算方法。

在Minor GC和Full GC执行过程中会收集一些历史数据,然后根据历史数据预测趋势值。在预测的时候使用衰减平均值来计算,在衰减计算中可以设置两个参数Weight和Padding,分别表示最新数据的权重、预测值调整衰减方差的倍数。

在上面新生代Eden和Old调整的公式中用到eden_desired、promoted_desired、minor_gc_cost和full_gc_cost,它们可以分为两类:大小的预测、时间的预测。大小的预测(eden_desired和promoted_desired)使用参数AdaptiveSizePolicyWeight和PromotedPadding,时间的预测(minor_gc_cost和full_gc_cost)使用参数AdaptiveTimeWeight和PausePadding。

其中eden_desired和promoted_desired使用的历史数据是每次Minor GC执行前Eden的大小及上一次执行Minor GC时所有晋升对象的大小(promoted)。收集每次Eden、promoted数据的建立序列,然后预测eden_desired和promoted_desired的值,预测时使用了参数AdaptiveSizePolicyWeight和PromotedPadding。

而minor_gc_cost和full_gc_cost是通过公式变化得到的。首先收集Minor GC、Full GC的执行时间(分别记为minor_pause、full_pause),然后再收集GC执行间隔的时间(记为interval),minor_gc_cost和full_gc_cost的计算方法如下:

收集每次minor_gc_cost、full_gc_cost数据的建立序列,然后预测minor_gc_cost、full_gc_cost的值,预测时使用了参数AdaptiveTimeWeight和PausePadding。

参数AdaptiveSizePolicyWeight、PromotedPadding、AdaptiveTimeWeight和PausePadding的默认值分别为10、3、25、1,分别表示在size预测时最新数据的权重为10%,使用3个衰减均方差调整预测值;在时间预测时最新数据的权重为25%,使用1个衰减均方差调整预测值。

除此之外,在参数
AdaptiveSizeThroughPutPolicy为1时,该模型建立预测吞吐量的变化。具体方法是:建立Minor GC和Full GC内存使用和停顿时间的关系。Minor GC使用序列{(eden_size1, minor_pause1), (eden_size2,minor_pause2), …, (eden_sizei, minor_pausei)},Full GC使用序列{(promoted_size1, full_pause1), (promoted_size2, full_pause2), …,(promoted_sizei, full_pausei)},通过序列建立size和pause之间的关系,然后可以预测吞吐量是否发生变化。预测时使用最小二乘法建立size和pause的函数关系。下面简单介绍一下最小二乘法。

给定一个点序列(x1, y1), (x2, y2), …, (xn, yn),寻找一条直线y =f(x) = ax + b,使得所有的点到直线的距离最小,然后再根据获得的直线预测未来的值。最小二乘法的关键是寻找函数的参数a和b。点序列到直线的距离记为d,则

要使得d最小,可以对a和b分别求导,并让其等于0,此时d最小,所以可以建立以下微分方程:

由此方程可以得到a和b的计算公式如下:

a和b公式中的n表示n个抽样数据。

根据最小二乘法的公式可以计算得到a和b,分别表示系数和截距。

1)a大于0,直线斜率为正,表示吞吐量的变化仍然是增加的。

2)a小于0,直线斜率为负,表示吞吐量的变化开始减少。

所以在模型预测时只要判断斜率a的变化情况就可以知道吞吐量的变化情况。当斜率a大于0时,由于吞吐量仍然增加,因此不调整Eden或者Old的大小;只有在斜率a小于0时,表示吞吐量开始减少,增加Eden或者Old的大小才可以提高吞吐量。

在根据停顿时间和内存使用效率调整策略时,会减少Eden或者Old的大小。在减少Eden或者Old的大小时,为了避免导致Mutator性能下降,使用了额外的参数控制减少的比例。真实减少的数值重用了eden_scaled和old_scaled的计算方法,减少值分别记为eden_decrement和old_decrement,公式如下:

参数
AdaptiveSizeDecrementScaleFactor的默认值为4,表示减少值是增加值的1/4。

以上参数用于设置在执行Minor GC和Full GC后,根据吞吐量调整新生代、老生代的大小时是否调整full_gc_cost的值,从而影响后续预测值的计算。

在老生代减少的计算过程中可能会因为Full GC发生的频率较低,进而导致full_gc_cost计算出现很大的误差。特别是会出现触发过几次Full GC后不再触发的情况,对于这样的情况,可以控制在计算full_gc_cost时是否进行额外的调整。

参数
UseAdaptiveSizeDecayMajorGCCost为true,表示允许在满足一定条件时对full_gc_cost进行调整,参数AdaptiveSizeMajorGCDecayTimeScale控制条件,具体条件是当上一次执行Full GC到现在为止过去的时间(记为time_since_last_full_gc)大于一定的阈值,则调整full_gc_cost。阈值(threshold)通过公式计算得到:

threshold =
AdaptiveSizeMajorGCDecayTimeScale×full_gc_costfull_gc_cost的调整公式为:

参数
UseAdaptiveSizeDecayMajorGCCost的默认值为true,表示允许调整full_gc_cost的值,参数AdaptiveSizeMajorGCDecayTimeScale的默认值为10,表示距离上次full_gc发生的时间至少是full_gc_cost的10倍才会进行调整。

新生代中的对象经过一定次数的Minor GC以后,如果对象仍然存活才会晋升到老生代。参数表示经过Minor GC最多的次数的阈值,参数的默认值为15。

晋升阈值的初始值,参数的默认值为7。

在Parallel GC中,如果UseAdaptiveSizePolicy为true,则初始值为7。

如果UseAdaptive-SizePolicy为false,则初始值为MaxTenuringThreshold。

该参数控制是否允许动态调整新生代中Survivor分区的大小及对象晋升的阈值,仅适用于Parallel GC。该参数在参数UseAdaptiveSizePolicy设置为true时才能生效。

Survivor分区的大小根据Survivor分区的历史值通过衰减平均法进行预测。

晋升阈值的调整与参数ThresholdTolerance相关。调整的方法根据MinorGC和Full GC回收时间(即minor_gc_cost和full_gc_cost)决定。参数ThresholdTolerance用于控制两个停顿时间的比例,晋升阈值调整的方法为:

1)如果

,则增加晋升阈值。

2)如果

,则减小晋升阈值。

参数
UsePSAdaptiveSurvivorSizePolicy的默认值为true。参数ThresholdTolerance的默认值为10,表示minor_gc_cost和full_gc_cost的比值在±10%内不调整阈值。

在Parallel GC中会动态地计算Survivor分区的大小。需要收集Survivor分区的大小,然后采用衰减平均预测。为了修正预测的准确性,使用参数AdaptiveSizePolicyWeight和SurvivorPadding,分别控制最新Survivor分区的大小的权重及预测时调整衰减均方差的倍数。

参数SurvivorPadding的默认值为3,表示预测Survivor分区大小使用3倍的衰减均方差进行调整。

该参数允许动态调整Parallel GC新生代和老生代的边界(不仅仅是大小,关于边界的调整请参见5.1.1节),这将增大或者减小新生代或者老生代最大的可用空间。该参数在参数UseAdaptiveSizePolicy设置为true时才能生效。

该参数用于在Parallel GC中控制是否输出内存调整前后的信息。该参数值为0,不输出。参数值不为0,表示每间隔
AdaptiveSizePolicyOutputInterval次GC后进行一次输出。参数的默认值为0。

JVM使用本地内存的估算值,默认值为256MB。该值不会影响JVM的运行,仅仅用于信息输出。无须设置。

在Parallel GC中,因为新生代和老生代可以动态调整(UseAdaptiveSizePolicy设置为true),其中Survivor的大小可以通过公式计算得到:

如果设置参数MinSurvivorRatio,那么参数值必须大于等于3,如果小于3,该值会被强制设置为3。参数的默认值为3,表示在允许调整Survivor分区的情况下,表示Survivor分区为新生代的1/3。当SurvivorRatio设置而该值没有设置时,MinSurvivorRatio = SurvivorRatio + 2。

在Parallel GC中,当新生代和老生代不能调整时,Survivor设置为

如果设置参数InitialSurvivorRatio,那么参数值必须大于等于3,如果小于3,该值会被强制设置为3。参数的默认值为8,表示在不允许调整Survivor分区的情况下,Survivor分区最大为新生代的1/8。

另外,当设置SurvivorRatio,而没有设置参数InitialSurvivorRatio时,MinSurvivorRatio = SurvivorRatio + 2。

  • 15
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
jvm内存模型和垃圾回收GC)是Java程序重要的概念。 Java虚拟机(JVM内存模型定义了Java程序对象的分配和回收。它包括了堆、栈、方法区和程序计数器。Java内存模型(JMM)则用于规定多线程环境下的内存访问和操作顺序。 GC是垃圾收集器自动完成的过程,用于回收不再使用的对象,释放内存空间。JVM会根据系统环境和内存需求来决定何时进行GC。我们也可以通过调用System.gc()方法手动触发一次垃圾回收,但是具体的回收时机由JVM决定。需要注意的是,手动调用System.gc()方法并不推荐,因为它会消耗较多的资源。 垃圾收集器是实现垃圾回收的具体实现。它们采用不同的算法和策略来收集和回收垃圾对象。Java有多种垃圾收集器可供选择,如Serial、Parallel、CMS(Concurrent Mark Sweep)和G1(Garbage-First)等。每个垃圾收集器都有不同的特点和适用场景,可以根据应用程序的需求进行选择和配置。 因此,JVM内存模型定义了对象的分配和回收方式,而垃圾回收器则是具体实现了垃圾回收的过程,根据不同的算法和策略来回收不再使用的对象。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [JVM内存模型与垃圾回收](https://blog.csdn.net/weixin_40980639/article/details/125934179)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值