Java和Go需要默认开启大内存分页吗?

771 阅读3分钟

本文来源于公众号:勾勾的Java宇宙(微信号:Javagogo)

原文链接:mp.weixin.qq.com/s/rCj9FWy7-… 作者:林䭽


在回答“需不需要”前,我想先说说这两个语言对大内存分页的支持。

当然,两门语言能够使用大内存分页的前提条件,是开启了操作系统的大内存分页,此处不是这篇文章的重点。满足这个条件后,我再来说说两门语言还需要做哪些配置。

Go

Go 是一门编译执行的语言。

在 Go 编译器的前端,源代码被转化为 AST;在 Go 编译器的后端,AST 经过若干优化步骤,转化为目标机器代码。因此 Go 的内存分配程序基本上可以直接和操作系统的 API 对应。因为 Go 没有虚拟机。

而且 Go 提供了一个底层的库 syscall,直接支持上百个系统调用,具体可以参考 Go 的官方文档。

其中的 syscall.madvise 系统调用,可以直接提示操作系统某个内存区间的程序是否使用大内存分页技术加速 TLB 的访问,这个也可以去参考 Linux 中 madise 的文档,这个工具的作用主要是提示操作系统如何使用某个区域的内存,开启大内存分页是它之中的一个选项。

下面的程序通过 malloc 分配内存,然后用 madvise 提示操作系统使用大内存分页的示例:

#include <sys/mman.h>
size_t size = 256*1024*1024;
char* mymemory = malloc(size);
madvise(mymemory, size, MADV_HUGEPAGE);

如果放到 Go 语言,那么需要用的是 runtime.sysAllocsyscall.Madvise 函数。

Java

JVM 是一个虚拟机,应用 Just-In-Time 在虚拟指令执行的过程中,将虚拟指令转换为机器码执行。

JVM 自己有一套完整的动态内存管理方案,而且提供了很多内存管理工具可选。在使用 JVM 时,虽然 Java 提供了 UnSafe 类帮助我们执行底层操作,但是通常情况下我们不会使用 UnSafe 类。一方面 UnSafe 类功能不全,另一方面看名字就知道它过于危险hhh。

Java 有一个虚拟机参数:XX:+UseLargePages,开启这个参数,JVM 会开始尝试使用大内存分页。

那么,到底该不该用大内存分页?

首先可以分析下你应用的特性,看看有没有大内存分页的需求。通常 OS 是 4K,你有没有需要反复用到大内存分页的场景。

另外你可以使用 perf 指令衡量你系统的一些性能指标,其中就包括 iTLB-load-miss,可以用来衡量 TLB Miss。如果发现自己系统的 TLB Miss 较高,那么就可以深入分析是否需要开启大内存分页。


公众号勾勾的Java宇宙(微信号:Javagogo)