JDK 1.8 -XX:+UseLargePages 在 os 上剩余的大页面不足时的行为
JDK 1.8 -XX:+UseLargePages behavior when there's not enough huge pages left on os
我目前对如何优化使用 HugePages 和 JVM 应用程序与 Netty,启用 -XX:+UseLargePages 选项,并使用 G1Gc[=26= 感到困惑].
另外,我没有忘记设置相同的堆和元空间的最大和最小大小。
我的应用程序看起来不错,但我想知道 如果系统上没有剩余的可用大页面 会发生什么,因为 JVM 使用额外的本机内存区域来分配直接内存缓冲区等。
(假设应用程序正常启动,并在堆外内存区域消耗额外的HugePages。)
我已阅读下一页,但没有描述 JVM 无法分配大页面时的行为。
https://www.oracle.com/java/technologies/javase/largememory-pages.html
我使用 CentOS 7 和 OpenJDK 1.8。0_151-b12 作为部署前的测试平台。
如果分配大页面失败,OpenJDK 8 或更高版本回退到分配常规页面。
src/hotspot/share/memory/virtualspace.cpp:
if (base != NULL) {
[...]
} else {
// failed; try to reserve regular memory below
if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) ||
!FLAG_IS_DEFAULT(LargePageSizeInBytes))) {
log_debug(gc, heap, coops)("Reserve regular memory without large pages");
}
}
所有 GC 实现都使用 ReservedSpace
助手来分配内存,因此这不是特定于 GC 的。
您可以通过限制可用的大页面轻松地在 Linux 上测试该行为:
$ echo 16 > /proc/sys/vm/nr_hugepages
$ cat /proc/meminfo | grep HugePages
AnonHugePages: 40960 kB
HugePages_Total: 16
HugePages_Free: 16
HugePages_Rsvd: 0
HugePages_Surp: 0
$ java -XX:+UseLargePages Test
OpenJDK 64-Bit Server VM warning: Failed to reserve large pages memory req_addr: 0x0000000000000000 bytes: 251658240 (errno = 12).
OpenJDK 64-Bit Server VM warning: Failed to reserve large pages memory req_addr: 0x0000000707c00000 bytes: 4164943872 (errno = 12).
OpenJDK 64-Bit Server VM warning: Failed to reserve large pages memory req_addr: 0x0000000000000000 bytes: 67108864 (errno = 12).
OpenJDK 64-Bit Server VM warning: Failed to reserve large pages memory req_addr: 0x0000000000000000 bytes: 67108864 (errno = 12).
$ echo $?
0
strace 确认失败的分配尝试和成功的重试,大小相同但没有 MAP_HUGETLB
:
11631 mmap(NULL, 251658240, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB, -1, 0) = -1 ENOMEM (Cannot allocate memory)
11631 mmap(NULL, 251658240, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0x7f35d489c000
我目前对如何优化使用 HugePages 和 JVM 应用程序与 Netty,启用 -XX:+UseLargePages 选项,并使用 G1Gc[=26= 感到困惑].
另外,我没有忘记设置相同的堆和元空间的最大和最小大小。
我的应用程序看起来不错,但我想知道 如果系统上没有剩余的可用大页面 会发生什么,因为 JVM 使用额外的本机内存区域来分配直接内存缓冲区等。
(假设应用程序正常启动,并在堆外内存区域消耗额外的HugePages。)
我已阅读下一页,但没有描述 JVM 无法分配大页面时的行为。 https://www.oracle.com/java/technologies/javase/largememory-pages.html
我使用 CentOS 7 和 OpenJDK 1.8。0_151-b12 作为部署前的测试平台。
如果分配大页面失败,OpenJDK 8 或更高版本回退到分配常规页面。
src/hotspot/share/memory/virtualspace.cpp:
if (base != NULL) {
[...]
} else {
// failed; try to reserve regular memory below
if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) ||
!FLAG_IS_DEFAULT(LargePageSizeInBytes))) {
log_debug(gc, heap, coops)("Reserve regular memory without large pages");
}
}
所有 GC 实现都使用 ReservedSpace
助手来分配内存,因此这不是特定于 GC 的。
您可以通过限制可用的大页面轻松地在 Linux 上测试该行为:
$ echo 16 > /proc/sys/vm/nr_hugepages
$ cat /proc/meminfo | grep HugePages
AnonHugePages: 40960 kB
HugePages_Total: 16
HugePages_Free: 16
HugePages_Rsvd: 0
HugePages_Surp: 0
$ java -XX:+UseLargePages Test
OpenJDK 64-Bit Server VM warning: Failed to reserve large pages memory req_addr: 0x0000000000000000 bytes: 251658240 (errno = 12).
OpenJDK 64-Bit Server VM warning: Failed to reserve large pages memory req_addr: 0x0000000707c00000 bytes: 4164943872 (errno = 12).
OpenJDK 64-Bit Server VM warning: Failed to reserve large pages memory req_addr: 0x0000000000000000 bytes: 67108864 (errno = 12).
OpenJDK 64-Bit Server VM warning: Failed to reserve large pages memory req_addr: 0x0000000000000000 bytes: 67108864 (errno = 12).
$ echo $?
0
strace 确认失败的分配尝试和成功的重试,大小相同但没有 MAP_HUGETLB
:
11631 mmap(NULL, 251658240, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB, -1, 0) = -1 ENOMEM (Cannot allocate memory)
11631 mmap(NULL, 251658240, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0x7f35d489c000