You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过JNI启动JVM的Linux进程占用4GiB虚拟内存问题排查

问题描述

在Red Hat Linux机器上,通过JNI实例化JVM的C++进程,仅启动进程(未实例化对象或调用任何库),用ps命令查看VSZ(虚拟内存大小)竟达到约4GiB。但相同Java版本的AIX系统中,VSZ仅为8MB,需要解释该差异原因。

复现代码

C++代码

// C++
#include <jni.h>
#include "unistd.h" // sleep

int main()
{
    JavaVMInitArgs vm_args = {};
    JNIEnv* env_ = 0;
    JavaVM* jvm_ = 0;

    vm_args.version = JNI_VERSION_1_8;
    jint res = JNI_CreateJavaVM(&jvm_, (void**)&env_, &vm_args);
    sleep(10);

    return 0;
}

Makefile

# Makefile
JAVA_HOME = /etc/alternatives/java_sdk
CPPFLAGS = -I$(JAVA_HOME)/include/linux -I$(JAVA_HOME)/include
LDFLAGS = -L$(JAVA_HOME)/jre/lib/amd64/server -ljvm

all: test

test: main.cpp
    $(CXX) $(CPPFLAGS) $< -o $@ $(LDFLAGS)

测试结果

Red Hat Linux环境

执行./test后等待2-3秒,运行以下命令:

$ ps -Ao"pid,time,vsize,rssize,pcpu,args" | grep -E "PID|test" | grep -v grep
    PID     TIME    VSZ   RSS %CPU COMMAND
 372587 00:00:00 4078292 25304 1.2 ./test

VSZ达到4GB,延长sleep时长也无变化,说明这不是初始化瞬间的临时现象,长期运行此类进程可能引发JVM堆空间相关问题。

AIX环境

$ ps -Ao"pid,time,vsize,rssize,pcpu,args" | grep -E "PID|test" | grep -v grep
     PID        TIME   VSZ   RSS  %CPU COMMAND
37552202    00:00:00  8544  8548   0.0 ./test

VSZ仅为8MB。

环境信息

两个系统使用的Java版本一致:

$ java -version
openjdk version "1.8.0_312"
OpenJDK Runtime Environment (build 1.8.0_312-b07)
OpenJDK 64-Bit Server VM (build 25.312-b07, mixed mode)

Red Hat系统版本:

$ cat /etc/os-release
NAME="Red Hat Enterprise Linux"
VERSION="8.3 (Ootpa)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="8.3"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Red Hat Enterprise Linux 8.3 (Ootpa)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:redhat:enterprise_linux:8.3:GA"
HOME_URL="https://www.redhat.com/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"

REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 8"
REDHAT_BUGZILLA_PRODUCT_VERSION=8.3
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="8.3"

原因分析

这个差异主要源于Linux和AIX系统的虚拟内存管理机制不同,以及OpenJDK在不同平台上的内存初始化策略差异:

  • Linux的内存预分配策略
    在Linux上,OpenJDK的Server VM默认会预分配整个Java堆的虚拟内存空间(即使实际还未使用物理内存)。JDK 8中Server VM的默认堆大小上限是4GB(-Xmx4g),这就是VSZ显示4GB的原因。虚拟内存预分配是Linux下JVM的默认行为,目的是减少后续内存分配时的开销,确保内存地址空间连续。需要注意的是,VSZ是进程的虚拟内存总大小,包含已分配但未实际使用的内存块,而RSS才是实际占用的物理内存(测试中RSS仅25MB左右),所以该现象不会立即消耗物理内存,但可能导致进程虚拟内存空间占用过大,在内存紧张的环境下影响其他进程。

  • AIX的内存管理机制
    AIX采用延迟内存分配(lazy allocation)策略,JVM在AIX上不会预先分配整个堆的虚拟内存,而是在实际需要时才逐步分配。此外,AIX的ps命令统计VSZ的方式也和Linux不同,它只统计已经实际提交(committed)的内存,而非预分配的虚拟内存空间,所以显示的VSZ远小于Linux。

  • JVM参数的影响
    如果在Linux上手动指定较小的堆大小(比如-Xmx256m),VSZ会相应减小。可以通过修改JavaVMInitArgs添加启动参数验证:

    vm_args.nOptions = 1;
    const char* options[] = {"-Xmx256m"};
    vm_args.options = (JavaVMOption*)malloc(vm_args.nOptions * sizeof(JavaVMOption));
    for (int i = 0; i < vm_args.nOptions; i++) {
        vm_args.options[i].optionString = (char*)options[i];
    }
    

    修改后进程的VSZ会显著降低。

内容的提问来源于stack exchange,提问作者ABu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 13:31:09