我编写了一个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的根本原因是什么。
答案 0 :(得分:0)
这不是测试应用程序响应能力的好方法。您应该在现实的工作负载下运行它多次,并使用监视工具和已启用的GC日志记录来观察应用程序行为。 然后,您可以判断GC引入的延迟是否可以接受。
完成后,您可以尝试改进代码和/或尝试使用不同的JVM设置。 并且可能会升级您使用的JDK版本,因为它似乎是8或更早的版本。
PS:要在GC日志中获取更多详细信息,还可以包括安全点统计信息(请参见https://blog.jayan.kandathil.ca/gc_logging_in_java11.html)。