JVM认知的常见10个误区

本文探讨了关于JVM的10个常见误解,包括OpenJDK8默认GC、最大堆内存设置、年轻代比例、内存分配策略、堆外内存管理、GC暂停时间、并发线程设置、GC性能评估、G1的长时间停顿以及ZGC的优势。总结了不同GC在吞吐量和延迟之间的权衡,以及适用场景的建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1、OpenJDK8的默认GC是不是CMS/G1?

2、默认最大堆内存是不是物理内存的1/4?

3、默认的年轻代最大值是不是一定是堆内存的1/3?

4、给JVM分配内存越多越好吗?

5、堆外内存很小,所以不用管?

6、所有的GC都会暂停(Stop The World)吗?

7、并发线程是CPU的1/8,并行线程是CPU的5/8吗?

8、是不是GC停顿越短系统性能就越好?

9、G1会不会发生长时间停顿的Full GC?

10、ZGC到底比G1/CMS/ParallelGC好在哪儿?

对于不同GC的常用场景总结


1、OpenJDK8的默认GC是不是CMS/G1?

各个版本默认GC策略。

JDK 6-8:默认Parallel GC

JDK9-18:默认G1 GC

GC发展历史:

Serial GC->Parallel GC->CMS GC->G1 GC->ZGC/Shenandoah GC

其中8、11、17为长期维护版本LTS版本。其中CMS在JDK9后被标记为废弃,JDK14后删除。

2、默认最大堆内存是不是物理内存的1/4?

简单说,必须是1024的倍数,且不能低于2M。

内存很小时,最大堆内存是物理内存的一半,其他情况是1/4,注意32位系统下最大物理内存就只有4G的限制。32位机器,最大1G;64位机器,最大可以超过32G(物理内存超过128G)。

参见:https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/parallel.html#default_heap_size

3、默认的年轻代最大值是不是一定是堆内存的1/3?

默认情况下,-XX:NewRatio默认是2,所以年轻代占比1(1+2) = 1/3

-Xmn/-XX:MaxNewSize,直接制定大小

G1:https://www.oracle.com/cn/technical-resources/articles/java/g1gc.html

G1默认是5%~60%:

-XX:G1NewSizePercent=5 -XX:G1MaxNewSizePercent=60

CMS很诡异。

CMS在内存较小时为:64M * 并发GC线程数(4) * 13 / 10 =332.8M
Young区内存最大值跟Xmx无关。如果上面计算的比Xmx的1/3大,则为1/3。

CMS:

Parallel GC和CMS GC的最大young区大小如何计算?

默认情况下,大小会受到自适应参数影响,我们先关掉此参数-XX:-UseAdaptiveSizePolicy。

然后试验如下:

java -Xmx1g -Xms1g -XX:-UseAdaptiveSizePolicy -XX:+UseParallelGC -jar target/gateway-server-0.0.1-SNAPSHOT.jar

MaxHeapSize = 1073741824 (1024.0MB)

NewSize = 357564416 (341.0MB)

MaxNewSize = 357564416 (341.0MB)

OldSize = 716177408 (683.0MB)

java -Xmx1g -Xms1g -XX:-UseAdaptiveSizePolicy -XX:+UseConcMarkSweepGC -jar target/gateway-server-0.0.1-SNAPSHOT.jar

MaxHeapSize = 1073741824 (1024.0MB)

NewSize = 348913664 (332.75MB)

MaxNewSize = 348913664 (332.75MB)

OldSize = 724828160 (691.25MB)

java -Xmx2g -Xms2g -XX:-UseAdaptiveSizePolicy -XX:+UseConcMarkSweepGC -jar target/gateway-server-0.0.1-SNAPSHOT.jar

MaxHeapSize = 2147483648 (2048.0MB)

NewSize = 348913664 (332.75MB)

MaxNewSize = 348913664 (332.75MB)

OldSize = 1798569984 (1715.25MB)

可以看到 ParallelGC下,young区大小为1024/3 = 341.3M,跟上述显示一致。

CMS情况下则为332.75M,不是1/3,并且在xmx为2048M时,还是332.75M,这说明最大young区大小与Xmx参数无关。

实际上,我的电脑上:64M * 并发GC线程数(4) * 13 / 10 =332.8M

这个式子是jvm代码写死的,只跟GC线程数有关系。

继续测试:

-XX:ParallelGCThreads=2

MaxHeapSize = 2147483648 (2048.0MB)

NewSize = 174456832 (166.375MB)

MaxNewSize = 174456832 (166.375MB)

OldSize = 1973026816 (1881.625MB)

-XX:ParallelGCThreads=8

MaxHeapSize = 2147483648 (2048.0MB)

NewSize = 697892864 (665.5625MB)

MaxNewSize = 697892864 (665.5625MB)

OldSize = 1449590784 (1382.4375MB)

证实了我们的猜测,并发线程为2时,大小为166M;线程为8时,为665M。

注意:线程数超过8的时候,会退化成按newRatio计算。

4、给JVM分配内存越多越好吗?

其他内存 = 虚拟机(少量) + 非堆 + 堆外

系统可用内存 = 全部内存 - 系统损耗(少量)

例如虚拟机或容器只有4G,如果配置-Xmx4g,JVM以为自己能用到4G,实际上堆内存到3.6G的时候,系统就没有内存了,这时候在想去使用内存,就一定会OOM。

1)永远建议 -Xmx=最大物理内存*[0.6~0.8]。物理内存4G,Xmx为2.4g~3.2g为佳。

2)堆越大,扫描复制的时间越长,建议在合适的范围内,尽量少一些内存。

5、堆外内存很小,所以不用管?

堆外内存 = 一般指Direct Memory,不受GC控制。

一般来说,JVM/Netty等都可能会使用堆外内存。

默认堆外内存可以跟堆内存一样大!!!

可以通过 -XX:MaxDirectMemorySize 限制。

6、所有的GC都会暂停(Stop The World)吗?

所有GC都可能会Stop The World:

  1. Serial GC/Parallel GC:全部停顿,差别只是串行和并行。
  2. CMS GC/G1:部分步骤停顿,其他步骤跟业务线程并发执行。(一个简单的分辨方式就是看GC日志里,步骤前面如果有Concurrent 就是并发执行,不STW,否则就是STW停顿。)
  3. ZGC/Shennandoah GC:大部分步骤都不暂停。

以办公区打扫卫生为例。

7、并发线程是CPU的1/8,并行线程是CPU的5/8吗?

GC是CPU密集型操作,所以垃圾回收使用所有CPU时效率最高。

ParallelGC时,因为STW了,所有CPU都可以用来做GC。

1. ParallelGCThreads 参数的默认值是:

CPU核心数 <= 8,则为 ParallelGCThreads=CPU核心数

CPU核心数 > 8,则为 ParallelGCThreads = CPU核心数 * 5/8 + 3 向下取整

16核的情况下,ParallelGCThreads = 13

32核的情况下,ParallelGCThreads = 23

64核的情况下,ParallelGCThreads = 43

并发GC时,只能使用一部分线程,其他线程留给业务线程做业务处理。

2. ConcGCThreads的默认值则为:

ConcGCThreads = (ParallelGCThreads + 3)/4 向下去整

ParallelGCThreads = 1~4时,ConcGCThreads = 1

ParallelGCThreads = 5~8时,ConcGCThreads = 2

ParallelGCThreads = 13~16时,ConcGCThreads = 4

8、是不是GC停顿越短系统性能就越好?

GC 是 吞吐量 和延迟 之间平衡的艺术。

一般情况下选择:

业务是关注吞吐还是延迟?堆内存是大还是小?

当然,相同的GC比如G1,在更高版本JDK表现更好。

低延迟的停顿,代价是业务运行的过程中,有一些线程/CPU拿去做垃圾处理了,所以整体来说,性能并不是最好。极端情况下,吞吐量ZGC 比G1 低15%,G1 可能比 Parallel GC少15%。

9、G1会不会发生长时间停顿的Full GC?

G1是否就一定比CMS/ParallelGC好?

Young GC:Young区满了。

Mixed GC:同时回收Young和Old。

Full GC:极端条件下退化成串行处理(JDK10后改成并行)。

详细过程今天就不聊了,大家自己复习。注意处理的步骤,参数和阈值。

10、ZGC到底比G1/CMS/ParallelGC好在哪儿?

非常低的延迟,适用于内存较大,延迟敏感的系统。

示例:32 G堆平均GC不到 3 ms

其他:

吞吐量问题:极端情况比G1低。

返还系统内存:xmx=xms时不时问题。

指针压缩:内存用量要比其他GC大。

JDK15全系统:JDK12-14之有linux版本的OpenJDK有ZGC。

对于不同GC的常用场景总结

选择正确的GC算法,唯一可行的方式就是去尝试,并找出不合理的地方,一般性的指导原则:

  1. 如果考虑吞吐优先,CPU尽量都用于处理业务,用 Parallel GC;
  2. 如果考虑有限的低延迟,且每次GC时间尽量短,用 CMS GC;
  3. 如果堆较大,同时希望整体来看平均GC时间可控,使用 G1 GC。

对于内存大小的考量:

  1. 一般4G以上,算是比较大,用 G1 GC 的性价比较高。
  2. 一般超过8G,比如16G-64G内存,非常推荐使用 G1 GC。
  3. 更大内存或者低延迟要求非常苛刻,用 ZGC 。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kimmking

赠人玫瑰手有余香

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值