为什么大型HashMap会导致长时间的GC暂停

时间:2019-07-08 02:26:58

标签: java garbage-collection jvm

我编写了一个GC暂停测试功能,当显式调用System.gc()时,发现带有大型HashMap(〜300万个条目)的STW时间较长(> 1.5s)。

我尝试了大的ArrayList,它显示了相同的长时间GC暂停(比Map短)。

测试代码如下:

package tool.gc;

import java.util.HashMap;
import java.util.Map;

public class HashMapTest {
  Map<Integer, byte[]> map = new HashMap<>();

  public static void main(String[] args) throws Exception {
    HashMapTest test = new HashMapTest();
    test.gcTestWithMap();
    System.out.println("prepare to gc, now:" + System.currentTimeMillis());
    while (true) {
      System.gc();
      System.out.println("finish a round of gc");
      Thread.sleep(4000);
    }
  }

  public void gcTestWithMap() {
    for (int i = 0; i < 3000000; i++) {
      byte[] bytes = new byte[2000];
      for (int j = 0; j < bytes.length; j++) {
        bytes[j] = 1;
      }
      map.put(i, bytes);
    }
  }
}

JVM启动参数:

java -Xmx10g -Xms10g  
-XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDetails  
-XX:+PrintGCDateStamps -XX:+PrintGCDetails  -Xloggc:gc.log 
-XX:+UseConcMarkSweepGC -XX:ParallelCMSThreads=8 
-cp test-1.0.0.jar tool.gc.HashMapTest

一些GC日志如下:

2019-07-08T10:27:35.386+0800: 438.306: Total time for which application threads were stopped: 2.1067575 seconds, Stopping threads took: 0.0000317 seconds
2019-07-08T10:27:37.386+0800: 440.306: Total time for which application threads were stopped: 0.0006364 seconds, Stopping threads took: 0.0000209 seconds
2019-07-08T10:27:38.298+0800: 441.218: Total time for which application threads were stopped: 0.0036499 seconds, Stopping threads took: 0.0000249 seconds
2019-07-08T10:27:41.143+0800: 444.063: Total time for which application threads were stopped: 1.7568843 seconds, Stopping threads took: 0.0000237 seconds
2019-07-08T10:27:41.144+0800: 444.064: Total time for which application threads were stopped: 0.0006293 seconds, Stopping threads took: 0.0000453 seconds
2019-07-08T10:27:42.033+0800: 444.953: Total time for which application threads were stopped: 0.0039319 seconds, Stopping threads took: 0.0000295 seconds

据我了解,HashMap对象可以是GC根目录之一,但不是所有条目。我的问题是:长STW的根本原因是什么。

1 个答案:

答案 0 :(得分:0)

这不是测试应用程序响应能力的好方法。您应该在现实的工作负载下运行它多次,并使用监视工具和已启用的GC日志记录来观察应用程序行为。 然后,您可以判断GC引入的延迟是否可以接受。

完成后,您可以尝试改进代码和/或尝试使用不同的JVM设置。 并且可能会升级您使用的JDK版本,因为它似乎是8或更早的版本。

PS:要在GC日志中获取更多详细信息,还可以包括安全点统计信息(请参见https://blog.jayan.kandathil.ca/gc_logging_in_java11.html)。