JDK17中关于ZGC的部分优化建议

ZGC是一个可扩展的低延迟垃圾回收器。ZGC 在执行所有耗时操作时都是并发进行的,不会停止应用线程的执行超过一毫秒。它适用于需要低延迟的应用程序。暂停时间与使用的堆大小无关。ZGC 对于从几百兆字节到 16TB 的堆大小都能良好工作。

ZGC版本的选择

ZGC存在两种版本,旧版本是不使用分代算法,新版本使用分代算法。
如果开启ZGC:
使用新版本的,分代的ZGC:

-XX:+UseZGC -XX:+ZGenerational -Xmx<size> -Xlog:gc*

使用旧版本,不使用分代的ZGC:

-XX:+UseZGC -Xmx<size> -Xlog:gc*

ZGC的常见优化

1 使用大页(Large Pages)

配置ZGC使用大页,通常会在吞吐量、延迟和启动时间等方面性能有不错的表现,而且并没有明显的缺点。
但是使用大页,通常需要使用Root权限。

大页是指比常规的 4KB 页面更大的内存页面,通常是 2MB 或 1GB 大小(这取决于系统的硬件架构和配置)。它们用于减少内存管理的开销,提高内存访问效率。使用大页时,操作系统将内存划分为更大的块来减少页面管理和映射的开销。

以Linux为例。
对于Linux x86, 大页的大小为 2MB.
假如我要设置堆使用16G,但是我需要至少留够2G提供给非堆内存使用。因此一共需要18G。
首先,我要配置Linux系统的大页池有足够的要求:

18GB ÷ 2MB = 9,216 huge pages
所以需要 9216 个huge pages。

$ echo 9216 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

受限于系统要求,可能不会成功,而且需要花费较多时间。

执行完成后,可以使用以下命令进行检查:

$ cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages

启动JVM时,添加配置参数:

-XX:+UseLargePages

2 使用透明大页

当kernel >= 4.7版本时,可以使用透明大页。

透明大页是大页技术的一种自动化实现,它让大页的使用对应用程序透明。也就是说,用户和应用程序不需要做任何特殊配置,内核会自动决定何时使用大页,并在需要时将大页映射到内存中。THP 使得应用程序能够从大页中受益,而不需要手动管理大页内存。

开启参数:

-XX:+UseLargePages -XX:+UseTransparentHugePages

前提是要现在Linux中开启透明大页的:

$ echo madvise > /sys/kernel/mm/transparent_hugepage/enabled

madvise() 是一个系统调用,用于提供内存建议,以优化内存管理。在 Linux 中,madvise 系统调用允许进程向操作系统内核提供有关如何处理内存区域的建议。通过这些建议,内核可以更高效地管理内存,从而提高应用程序的性能或降低内存占用。

ZGC 使用shmem大页作为堆内存,所以还需要进行配置,将共享内存区域配置为使用大页面:

echo advise > /sys/kernel/mm/transparent_hugepage/shmem_enabled

共享内存(shmem)是一个特殊的内存区域,可以被多个进程共享。这使得多个进程可以访问相同的内存区域,避免了重复的内存分配,提高了内存的使用效率和性能。共享内存通常用于进程间通信(IPC)和缓存的共享。

透明大页的相关文档

3 启用NUMA支持

NUMA(Non-Uniform Memory Access) 是一种多处理器计算架构,旨在提高具有多个处理器(CPU)系统的内存访问效率。在 NUMA 架构中,计算机系统的内存被分为多个区域或“节点”,每个处理器都与一个或多个内存区域(节点)直接关联。与传统的对称多处理器(SMP)系统不同,NUMA 允许每个处理器拥有自己的本地内存区域,并且也能够访问其他处理器的内存区域,但访问其他内存区域的速度会比较慢。

ZGC支持NUMA,会尝试把Java堆分配到NUMA的本地内存。这个是默认开启的。
如果你要明确地开启:

XX:+UseNUMA

4 可以使用GC日志

启用参数:

-Xlog:gc*:gc.log

gc* 把开头带gc的日志都写入
gc.log 表示把日志写入名为gc.log的文件

5 归还未使用的内存给操作系统

通常不建议使用该功能。
这个功能对于关注程序和环境非常有用。但是对Java线程的延迟有不好的影响。
可以通过以下命令关闭:

-XX:-ZUncommit

6 设置堆大小

ZGC最重要的调整,就是调整Java堆的大小。可以通过-Xmx进行调整。
因为ZGC是一个并发收集器, 所以必须要有足够的堆大小可以容纳程序的生产大小。通常来说,设置越大的内存肯定是越好的。但是,并不建议浪费太多的内存。
ZGC有一个有意思的配置,-XX:SoftMaxHeapSize。可以使用该配置软设置一个Java堆可以使用的大小。如:

 -Xmx5g -XX:SoftMaxHeapSize=4g

在这个例子里,ZGC 将使用 4GB 作为其限制,但如果它无法将堆大小保持在 4GB 以下,它仍然允许临时使用最多5GB。

posted @ 2024-11-26 18:14  吉姆雷诺  阅读(50)  评论(0编辑  收藏  举报