首页 > 解决方案 > JDK 1.8 -XX:+UseLargePages 操作系统上没有足够大页面时的行为

问题描述

我目前对如何使用带有 Netty、-XX:+UseLargePages选项和使用G1Gc的 JVM 应用程序优化使用 HugePages 感到困惑。
此外,我没有忘记设置相同的堆和元空间的最大和最小大小。

我的应用程序看起来不错,但我想知道如果系统上没有剩余的可用大页面会发生什么,因为 JVM 使用额外的本机内存区域来分配直接内存缓冲区等。
(假设应用程序正常启动,并在关闭时消耗额外的 HugePages -堆内存区域。)

我已阅读以下页面,但没有描述 JVM 无法分配大页面时的行为。 https://www.oracle.com/java/technologies/javase/largememory-pages.html

在部署之前,我使用 CentOS 7 和 OpenJDK 1.8.0_151-b12 作为测试平台。

标签: linuxjvmhuge-pages

解决方案


如果分配大页面失败,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 实现都使用ReservedSpacehelper 来分配内存,因此这不是 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

推荐阅读