是否默认启用G1垃圾收集器的String Deduplication功能?

时间:2017-10-03 04:51:10

标签: java jvm java-9 g1gc

Java 8 Update 20中实现的

JEP 192: String Deduplication in G1添加了新的String重复数据删除功能:

  

通过增强G1垃圾收集器来减少Java堆实时数据集,以便自动连续地对重复的String实例进行重复数据删除。

JEP页面提到命令行选项UseStringDeduplication (bool)允许启用或禁用重复数据删除功能。但是JEP页面并没有指出默认值。

➠与Java 8和Java 9捆绑在一起的G1垃圾收集器中,重复数据删除功能是默认开启还是关闭?

➠是否有“getter”方法在运行时验证当前设置?

我不知道在JEP页面之外的哪个地方寻找文档。

至少在配备HotSpot的Java 9实现中,G1 garbage collectorenabled by default。这个事实现在促成了这个问题。有关字符串实习和重复数据删除的详细信息,请参阅29:00的this 2014-10 presentation by Aleksey Shipilev

2 个答案:

答案 0 :(得分:14)

字符串重复数据删除关闭默认情况下

对于下面看到的Java 8和Java 9版本,UseStringDeduplication默认为false(禁用)。

验证功能设置的一种方法:list out all the final flags for JVM然后查找它。

构建1.8.0_131-b11

    $ java -XX:+UseG1GC  -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version | grep -i 'duplicat'
     bool PrintStringDeduplicationStatistics        = false                               {product}
    uintx StringDeduplicationAgeThreshold           = 3                                   {product}
     bool StringDeduplicationRehashALot             = false                               {diagnostic}
     bool StringDeduplicationResizeALot             = false                               {diagnostic}
     bool UseStringDeduplication                    = false                               {product}
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

构建9 + 18

    $ java -XX:+UseG1GC  -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version | grep -i 'duplicat'
    uintx StringDeduplicationAgeThreshold          = 3                                        {product} {default}
     bool StringDeduplicationRehashALot            = false                                 {diagnostic} {default}
     bool StringDeduplicationResizeALot            = false                                 {diagnostic} {default}
     bool UseStringDeduplication                   = false                                    {product} {default}
java version "9"
Java(TM) SE Runtime Environment (build 9+181)
Java HotSpot(TM) 64-Bit Server VM (build 9+181, mixed mode)

测试它的另一种方法是使用

package jvm;

import java.util.ArrayList;
import java.util.List;

public class StringDeDuplicationTester {

    public static void main(String[] args) throws Exception {
        List<String> strings = new ArrayList<>();
        while (true) {
            for (int i = 0; i < 100_00; i++) {
                strings.add(new String("String " + i));
            }
            Thread.sleep(100);
        }
    }
}

在没有明确指定的情况下运行。

$ java  -Xmx256m -XX:+UseG1GC -XX:+PrintStringDeduplicationStatistics jvm.StringDeDuplicationTester
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at jvm.StringDeDuplicationTester.main(StringDeDuplicationTester.java:12)

明确打开时运行。

$ java  -Xmx256m -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+PrintStringDeduplicationStatistics jvm.StringDeDuplicationTester
[GC concurrent-string-deduplication, 5116.7K->408.7K(4708.0K), avg 92.0%, 0.0246084 secs]
   [Last Exec: 0.0246084 secs, Idle: 1.7075173 secs, Blocked: 0/0.0000000 secs]
      [Inspected:          130568]
         [Skipped:              0(  0.0%)]
         [Hashed:          130450( 99.9%)]
         [Known:                0(  0.0%)]
         [New:             130568(100.0%)   5116.7K]
      [Deduplicated:       120388( 92.2%)   4708.0K( 92.0%)]
         [Young:                0(  0.0%)      0.0B(  0.0%)]
         [Old:             120388(100.0%)   4708.0K(100.0%)]
   [Total Exec: 1/0.0246084 secs, Idle: 1/1.7075173 secs, Blocked: 0/0.0000000 secs]
      [Inspected:          130568]
         [Skipped:              0(  0.0%)]
         [Hashed:          130450( 99.9%)]
         [Known:                0(  0.0%)]
         [New:             130568(100.0%)   5116.7K]
      [Deduplicated:       120388( 92.2%)   4708.0K( 92.0%)]
         [Young:                0(  0.0%)      0.0B(  0.0%)]
         [Old:             120388(100.0%)   4708.0K(100.0%)]
   [Table]
      [Memory Usage: 264.9K]
      [Size: 1024, Min: 1024, Max: 16777216]
      [Entries: 10962, Load: 1070.5%, Cached: 0, Added: 10962, Removed: 0]
      [Resize Count: 0, Shrink Threshold: 682(66.7%), Grow Threshold: 2048(200.0%)]
      [Rehash Count: 0, Rehash Threshold: 120, Hash Seed: 0x0]
      [Age Threshold: 3]
   [Queue]
      [Dropped: 0]
[GC concurrent-string-deduplication, deleted 0 entries, 0.0000008 secs]
...
output truncated

<子> 注意:此输出来自build 1.8.0_131-b11。看起来Java 9没有打印字符串重复数据删除统计信息的选项。潜在的错误? 即可。统一日志记录杀死了此特定选项

$ java  -Xmx256m -XX:+UseG1GC -XX:+PrintStringDeduplicationStatistics -version
Unrecognized VM option 'PrintStringDeduplicationStatistics'
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

答案 1 :(得分:9)

尽管Jigar已经准确地提供了了解JVM标志和统计数据的方法,但是仍然链接到一些有用的文档来解决这部分问题:

  

我不知道在JEP页面之外查找文档的位置。

  

在JDK 9中,当垃圾收集器时,默认垃圾收集器是G1   未明确指定。

  • 详细说明标志用法的java tool

    -XX:+UseStringDeduplication
    
  

启用字符串重复数据删除。 默认情况下,此选项已停用 。至   使用此选项,您必须启用垃圾优先(G1)垃圾   收集器。

     

字符串重复数据删除减少了String对象的内存占用量   Java堆通过利用许多String对象的事实   是相同的。而不是每个String对象指向它自己   字符数组,相同的String对象可以指向和共享   相同的字符数组。

如果

也解决那里的未决问题
  

Java 9无法打印字符串重复数据删除统计信息。

在Java9中使用 JEP 158:Unified JVM Logging 实现,垃圾收集器标记被标记为遗留,并且使用 -Xlog 功能。列出了将GC Logging Flags转换为Xlog的替换的详细列表here。其中一个建议替换

PrintStringDeduplicationStatistics  =>   -Xlog:stringdedup*=debug