首页 > 编程知识 正文

gc吞吐量,jvm参数大全

时间:2023-05-06 07:52:26 阅读:131385 作者:3020

实践中,对大部分应用领域,评价了一种垃圾回收(GC )算法是如何基于以下两个标准的:

吞吐量越高算法越好,暂停时间越短算法越好。 首先让我们来阐明垃圾回收(GC )的两个术语:“:吞吐量”(throughput )和“暂停时间”(pause times )。 JVM在专用线程(GC threads )上运行GC。 只要GC线程处于活动状态,它就会与“APP应用程序线程”(application threads )竞争当前可用CPU的时钟周期。 简单地说,吞吐量是指APP应用程序线程在程序总使用中所占的百分比。 例如,吞吐量为99/100意味着在100秒的程序运行时间内运行了99秒的APP应用程序线程,而GC线程只运行了1秒。

“暂停时间”是指APP应用程序线程完全暂停与GC线程的执行的时间。 例如,GC期间100毫秒的暂停时间意味着在此100毫秒期间APP应用程序线程不活动。 如果正在运行的APP应用程序具有100毫秒的“平均暂停时间”,则该APP应用程序的所有暂停时间的平均长度为100毫秒。 同样,100毫秒的“最大暂停时间”意味着该APP应用程序的所有暂停时间最多不超过100毫秒。

吞吐量VS暂停时间高吞吐量是因为APP应用程序的最终用户会觉得只有APP应用程序线程在进行“高工作效率”的工作。 直观地说,吞吐量越高,程序运行得越快。 暂停时间之所以低,是因为从最终用户的角度来看,无论是GC还是其他原因导致的APP应用程序暂停总是不好的。 这取决于APP应用程序的类型,暂停200毫秒可能会中断最终用户体验。 因此,最大暂停时间很低很重要,特别是在交互式APP应用中。

遗憾的是,“高通量”和“低休眠时间”是竞争的目标(矛盾)。 这样想来,为了简明起见,GC需要一定的前提条件才能安全运行。 例如,APP应用程序线程必须确保GC线程在尝试确定仍在引用和未引用的对象时不会更改对象的状态。 为此,APP应用程序必须在GC期间停止。 或者,根据使用的算法,仅在GC的特定阶段停止。 但是线程调度开销会增加。 直接开销是上下文开关,间接开销是缓存的影响。 除了JVM内部的安全开销之外,这还意味着GC及其带来的不可忽视的开销将增加GC线程执行实际工作的时间。 因此,可以通过尽可能少地运行GC来最大化吞吐量。 例如,仅在不可避免的时候运行GC可以节省所有与其相关的开销。

但是,如果只是偶尔运行GC,在此期间在堆中存储的对象数量很大,这意味着每次运行GC都需要做很多工作。 完成单个GC需要更多时间,平均和最大暂停时间会更长。 因此,考虑到暂停时间短,期望频繁地执行GC以更快地完成。 这反过来增加了开销,降低了吞吐量,我们又回到了起点。

综上所述,在设计(或使用) GC算法时?我们必须确定目标: GC算法? 只关注两个目标之一,即最大吞吐量和最小休眠时间,或者尝试找到两者之间的折衷。

HotSpot虚拟机垃圾回收本系列的第五部分介绍了年轻一代的垃圾回收器。 对于老一代,HotSpot虚拟机提供两种类型的垃圾回收算法,新的G1垃圾回收算法除外。 第一种算法尝试最大化吞吐量,第二种算法尝试最小化暂停时间。 今天我们的重点是第一类、“面向吞吐量”的垃圾收集算法。

因为我想重点讨论JVM配置参数,所以我只概述了HotSpot提供的面向吞吐量的垃圾回收算法。 在当年的上一代中,如果由于空间不足而导致对象分配失败,则会启动垃圾收集器。 “分配”通常是指从年轻一代提升到老一代的对象。 从所谓的“GC根”(GC roots ),在堆中搜索可到达的对象并将其标记为活的,然后垃圾收集器将活的对象移动到旧世代的未碎片化)存储器块中,剩下的内存空间为空也就是说,我们不会像年轻一代的垃圾收集算法所做的那样,像复制策略那样移动到不同的堆区域。 而是将所有对象放在一个堆区域中,并对该堆区域进行碎片整理。 垃圾收集器使用一个或多个线程执行垃圾回收。 如果使用多个线程,则算法的不同步骤被分解,因此每个收集线程通常在自己的区域中操作,而不干扰其他线程。 在垃圾回收期间,所有APP应用程序线程都将暂停,并在垃圾回收完成后重新启动。 看看与面向吞吐量的垃圾回收算法相关的重要JVM配置参数。

-使用此标志激活串行垃圾收集器,例如针对-XX: UseSerialGC单线程吞吐量垃圾收集器。 年轻一代和老一代都只有一个线程执行垃圾收集。 对于只有一个可用处理器内核的JVM,建议使用此标志。 在这种情况下,使用多个垃圾回收线程会冲突CPU资源并产生同步开销,但可能会产生相反的效果,因为它们从未真正并行执行。

-XX: UseParallelGC具有此标记,并告知JVM使用多线程并行执行年轻一代的垃圾回收。 我认为在Java 6上不应该使用这个标志。 因为-XX: UseParallelOldGC明显更合适。 需要注意的是,在Java 7中这种情况发生了一些变化。 -XX: UseParallelGC提供的效果与-XX: UseParallelOldGC相同。

-XX: UseParallelOldGC这个标志的命名有点不凑巧。 因为“旧”听起来“过时”。 但是,“老”实际上是指年老的一代,

这也解释了为什么-XX:+UseParallelOldGC要优于-XX:+UseParallelGC:除了激活年轻代并行垃圾收集,也激活了年老代并行垃圾收集。 当期望高吞吐量,并且JVM有两个或更多可用处理器核心时,我建议使用该标志。
作为旁注,HotSpot的并行面向吞吐量垃圾收集算法通常称为”吞吐量收集器”,因为它们旨在通过并行执行来提高吞吐量。

-XX:ParallelGCThreads

通过-XX:ParallelGCThreads=<value>我们可以指定并行垃圾收集的线程数量。 例如,-XX:ParallelGCThreads=6表示每次并行垃圾收集将有6个线程执行。 如果不明确设置该标志,虚拟机将使用基于可用(虚拟)处理器数量计算的默认值。 决定因素是由Java Runtime。availableProcessors()方法的返回值N,如果N<=8,并行垃圾收集器将使用N个垃圾收集线程,如果N>8个可用处理器,垃圾收集线程数量应为3+5N/8。
当JVM独占地使用系统和处理器时使用默认设置更有意义。 但是,如果有多个JVM(或其他耗CPU的系统)在同一台机器上运行,我们应该使用-XX:ParallelGCThreads来减少垃圾收集线程数到一个适当的值。 例如,如果4个以服务器方式运行的JVM同时跑在在一个具有16核处理器的机器上,设置-XX:ParallelGCThreads=4是明智的,它能使不同JVM的垃圾收集器不会相互干扰。

-XX:-UseAdaptiveSizePolicy

吞吐量垃圾收集器提供了一个有趣的(但常见,至少在现代JVM上)机制以提高垃圾收集配置的用户友好性。 这种机制被看做是HotSpot在Java 5中引入的”人体工程学”概念的一部分。 通过人体工程学,垃圾收集器能将堆大小动态变动像GC设置一样应用到不同的堆区域,只要有证据表明这些变动将能提高GC性能。 “提高GC性能”的确切含义可以由用户通过-XX:GCTimeRatio和-XX:MaxGCPauseMillis(见下文)标记来指定。
重要的是要知道人体工程学是默认激活的。 这很好,因为自适应行为是JVM最大优势之一。 不过,有时我们需要非常清楚对于特定应用什么样的设置是最合适的,在这些情况下,我们可能不希望JVM混乱我们的设置。 每当我们发现处于这种情况时,我们可以考虑通过-XX:-UseAdaptiveSizePolicy停用一些人体工程学。

-XX:GCTimeRatio

通过-XX:GCTimeRatio=<value>我们告诉JVM吞吐量要达到的目标值。 更准确地说,-XX:GCTimeRatio=N指定目标应用程序线程的执行时间(与总的程序执行时间)达到N/(N+1)的目标比值。 例如,通过-XX:GCTimeRatio=9我们要求应用程序线程在整个执行时间中至少9/10是活动的(因此,GC线程占用其余1/10)。 基于运行时的测量,JVM将会尝试修改堆和GC设置以期达到目标吞吐量。 -XX:GCTimeRatio的默认值是99,也就是说,应用程序线程应该运行至少99%的总执行时间。

-XX:MaxGCPauseMillis

通过-XX:GCTimeRatio=<value>告诉JVM最大暂停时间的目标值(以毫秒为单位)。 在运行时,吞吐量收集器计算在暂停期间观察到的统计数据(加权平均和标准偏差)。 如果统计表明正在经历的暂停其时间存在超过目标值的风险时,JVM会修改堆和GC设置以降低它们。 需要注意的是,年轻代和年老代垃圾收集的统计数据是分开计算的,还要注意,默认情况下,最大暂停时间没有被设置。
如果最大暂停时间和最小吞吐量同时设置了目标值,实现最大暂停时间目标具有更高的优先级。 当然,无法保证JVM将一定能达到任一目标,即使它会努力去做。 最后,一切都取决于手头应用程序的行为。
当设置最大暂停时间目标时,我们应注意不要选择太小的值。 正如我们现在所知道的,为了保持低暂停时间,JVM需要增加GC次数,那样可能会严重影响可达到的吞吐量。 这就是为什么对于要求低暂停时间作为主要目标的应用程序(大多数是Web应用程序),我会建议不要使用吞吐量收集器,而是选择CMS收集器。 CMS收集器是本系列下一部分的主题。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。