プロジェクト

全般

プロフィール

Linux上のJavaプロセスの仮想メモリサイズ

高橋 徹 さんが約8年前に追加

JavaのプロセスをLinuxで動かしている環境で、topコマンドを見るとVIRT(仮想メモリ)が著しく大きなプロセスとして悪目立ちします。
CentOS 6.8(64bit)上でOpenJDK 1.8.0_91 64bit VMの場合の例を次に示します。

top - 09:44:01 up 41 days, 21:31,  3 users,  load average: 0.49, 0.51, 0.44
Tasks: 115 total,   1 running, 114 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.7%us,  0.3%sy,  0.0%ni, 99.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   1020132k total,   845956k used,   174176k free,    30296k buffers
Swap:  2064380k total,    13904k used,  2050476k free,   493900k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
10558 gitbucke  20   0 2523m 143m 9792 S  0.7 14.4   0:56.25 java
11049 root      20   0 15024 1268  960 R  0.3  0.1   0:00.01 top
    1 root      20   0 23500 1104  908 S  0.0  0.1   0:00.68 init

VIRTサイズが2.4GBとなってびっくりします。物理メモリ使用量は、143MBとまあ妥当なところなのですが。

ヒープサイズを小さくすればいいのでは?と思い、-Xmx512m を入れてもこの値は変わりません(少し減るかも)。
VIRT(仮想メモリサイズ)なので気にすることはない、という意見もあり(賛同)、ほっといてもいいのですが、Javaを知らないLinux管理者からチクチク言われることになるかもしれません。

この件について少ししらべると、次のブログが見つかりました。

Java 8 and Virtual Memory on Linux

ヒープサイズ(-Xmx)を指定してもtopコマンドのVIRTサイズは遥かに大きい値を示す。
glibc 2.10以降で arena 機能が導入され、それが影響している。
64bit OSではMALLOC_ARENA_MAXのデフォルト値が128(64MBのブロックを最大で128個取るので、128スレッドがmallocしたときで8GBの仮想メモリを使用)。
arena 機能は多数のスレッドがメモリ確保する際の性能を高めるが、JavaではJava側でメモリ管理しているのでarena機能はほぼ不要。
Java 8からPermGenが無くなってMetaspaceが導入、これはネイティブヒープなのでmallocが多数使われ、arena機能の影響をより大きく受けるようになった。
環境変数 MALLOC_ARENA_MAX に小さな値(2とか3とか)を設定することで緩和は可能。