欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Java 8 GC 调优】确定 “代” 的大小

程序员文章站 2022-05-30 10:54:30
...

很多参数会影响 “代” 的大小。下图说明了堆中“已提交空间”和“虚拟空间”之间的区别。JVM 初始化时会为堆预留整个空间。可以通过 -Xmx 选项指定这个预留空间的大小。如果参数 -Xms 的值比 -Xmx 小,那么不会把所有的预留空间都提交给 JVM。这些未提交的空间在图中被标为 “virtual”(虚拟空间)。堆的不同部分(新生代和老年代)可根据需要增长到虚拟空间的极限。
 

某些参数是堆中 一部分与另一部分 的比率。如,NewRatio 表示老年代与新生代的相对大小。
 

【Java 8 GC 调优】确定 “代” 的大小
            
    
    博客分类: Java  
 

 

堆的总容量

以下关于 堆的增长和收缩 及 默认堆大小 不适用于并行GC。(可查看《并行GC》了解 并行GC 堆大小调整 与 默认堆大小 的信息。)但是控制 “堆的总大小” 和 “‘代’的大小” 的参数适用于 并行GC。
 

影响 GC 性能的最重要因素是 总可用内存。因为 GC 操作发生在“代”满时,吞吐量 与 可用内存量 成反比。
 

默认情况下,JVM 会增大或缩小“代”,以尝试将 可用空间的比例 保持在特定范围内。这个“范围”是个百分比,可以通过参数 -XX:MinHeapFreeRatio= 和 -XX:MaxHeapFreeRatio= 指定。
-Xms 设定了堆的最小容量,-Xmx 设定了堆的最大容量。
下表展示了这些参数在 64位 Solaris(SPARC平台版)上的默认值。

参数 默认值
MinHeapFreeRatio 40
MaxHeapFreeRatio 70
-Xms 6656K
-Xmx 通过计算得到

 

根据这些参数,如果某个“代”中的可用空间低于40%,则 JVM 会扩大该“代”的容量以保持40%的可用空间,直到达到该“代”的容量上限。
类似的,如果可用空间超过70%,那么“代”会被缩小,使得其只有70%的可用空间,当然也取决于它的容量下限。
 

正如上表所示,堆大小的默认最大值是 JVM 计算得到的。该计算方法之前被用在 并行GC 上,现在所有 GC 都在用。其中关于堆大小最大值的上限计算在 32位平台 和 64位平台 中是不同的(《堆容量 的 默认值》)。对客户端 JVM 也有类似的计算,这导致它的最大堆大小 小于 服务端 JVM。
 

一般准则

以下是关于 服务器应用 堆大小 的一般准则:

  • 除非暂停时间太长,否则尝试分配尽可能多的内存。默认值通常都太小了。
  • 将 -Xms 和 -Xmx 设置为相同值,可以移除大小调整策略,从而提高可预测性。但是如果你选择不当,JVM 无法补偿。
  • 通常,如果增加了CPU核数,就可以增大内存,因为内存分配是可以并行的。(以此提高内存分配效率)

 

新生代

在总可用内存之后,影响 GC 性能的最重要因素是 新生代的份额
新生代越大,Minor GC 的频率就越小。但是,对于有限的堆容量,更大的新生代意味着更小的老年代,这会增大 Major GC 的频率。
最佳选择取决于应用程序所分配对象的寿命分布。
 

默认情况下,新生代的容量由参数 NewRatio 控制。如,-XX:NewRatio=3 表示新生代与老年代的比例为 1:3 。也就是说,新生代(Eden 和 2个 Survivor)占总堆的 1/4 。
 

参数 NewSizeMaxNewSize 确定了新生代容量的 下限和上限。将这两个参数设置为相同的值 可以 固定新生代的大小。就如同 -Xms 和 -Xmx 相同时会固定堆的总容量。对于 NewRatio 的整数倍调整来说,这种更细粒度的新生代调整是很有用的。
 

Survivor

你可以使用参数 SurvivorRatio 来调整 Survivor 的容量,但这通常对性能并不重要
例,-XX:SurvivorRatio=6 表示将 Eden 和 一个Survivor 的比例设置为 1:6 。也就是说,每个 Survivor 都是 Eden 的 1/6 ,也就是新生代的 1/8 (不是 1/7,因为有 2个Survivor)。
 

  • 如果 Survivor 太小,GC 复制对象时会直接溢出到老年代。
  • 如果 Survivor 太大,它们也是毫无用处地空着。

每次 GC 时,JVM 都会选择一个阈值,来表示对象被转到 老年代 前可以复制的次数。这个阈值的选择是为了让 Survivor 保持半满(有2个Survivor)。命令行选项 -XX:+PrintTenuringDistribution 可用于显示此阈值 及新生代中对象的“年龄”(被复制的次数)。(注意:此选项并不是所有 GC 都适用。)这对于观察对象寿命分布是很用的。

 

下表展示了这些参数在 64位 Solaris 上的默认值。

参数 Server JVM 中的默认值
NewRatio 2
NewSize 1310M
MaxNewSize 无限制
SurvivorRatio 8

 

新生代的最大容量 是根据 堆的总容量 和 NewRatio 参数 计算得到的。MaxNewSize 的默认值 “无限制” 表示 “除非通过命令行设置了 MaxNewSize,否则不受限制”。
 

一般准则

以下是针对服务器应用的一般准则:

  • 先确定可以提供给 JVM 的 堆容量 最大值。然后根据新生代的规模来规划性能指标,找到最佳设置。
    注意:堆容量 的最大值应小于机器上的内存数量,以免过多的内存换页与抖动(短时间内大量换页操作就是抖动)。
  • 如果堆的总容量是固定的,那么增大新生代就需要减小老年代。
    保持老年代足够大,让它在任何时刻都能存放应用程序的所有存活数据,外加一些空闲空间(10%~20% 或 更多)
  • 给新生代充足的内存
  • 如果增加了CPU核数,就可以增大内存,因为内存分配是可以并行的

 

  • 【Java 8 GC 调优】确定 “代” 的大小
            
    
    博客分类: Java  
  • 大小: 9.9 KB