关于native memory不足引起的OutOfMemory(OOM)问题

本文探讨了Java应用程序在处理大文件时遇到的内存溢出问题,特别是由Native Memory不足导致的OutOfMemoryError。通过实验对比不同JVM堆配置下的表现,揭示了32位操作系统下Heap与Native Memory之间的平衡关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

environment
1.os=>win32 2GB RAM
2.jdk=>
D:\tools\native_memory>java -version
java version "1.6.0_27"
Java(TM) SE Runtime Environment (build 1.6.0_27-b07)
Java HotSpot(TM) Client VM (build 20.2-b06, mixed mode, sharing)

3.demo code
////////begin///////
import java.awt.*;
import java.io.*;

public class ReadLargeFileUnderExhastedNativeMemory {

public static void main(String[] args) {
try {


String filePath="D:\\work\\vm_files\\NeoShineLinux\\564d4057-070e-3aec-6046-7a461ab5d73e.vmem";//27m
//D:\\work\\vm_files\\NeoShineLinux\\564d4057-070e-3aec-6046-7a461ab5d73e.vmem;//256m
//D:\\work\\to_removed\\NC.doc;

FileInputStream fis = new FileInputStream(filePath); // Any file with size >= 501*501*501*2

int fileSize=fis.available();

System.out.println("=fileSize is ="+fileSize+"=end=");

byte buf[] = new byte[fileSize];

fis.read(buf);

System.out.println("buf ok");

}
catch (Exception e) {
e.printStackTrace();
System.out.println(e);
System.out.println();
}
}
/////////end///////
4.读取的文件大小为256M时,
(1)、由native memory不足引起的OOM问题,因为JVM分配了太多的内存(1400M)
D:\tools\native_memory>java -Xms1400m -Xmx1400m ReadLargeFileUnderExhastedNativeMemory
=fileSize is =268435456=end=
Exception in thread "main" java.lang.OutOfMemoryError
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:198)
at ReadLargeFileUnderExhastedNativeMemory.main(ReadLargeFileUnderExhastedNativeMemory.java:22)
(2)、正常读取,因为JVM分配较小的内存(512M)
D:\tools\native_memory>java -Xms512m -Xmx512m ReadLargeFileUnderExhastedNativeMemory
=fileSize is =268435456=end=
buf ok
5.【结论】
注意日志,java.lang.OutOfMemoryError,java.io.FileInputStream.readBytes(Native Method),反映的是由于native memory不足导致的OOM问题,
而不是由Java heap不足引起的。此时要考虑发生这种问题的原因,是由于native memory内存不足,另外需要注意以下事实,
在32-bit的os中,address space最大到4G,而address space又划分为kernel space和user space。windows 32bit下,默认的kernel space和user space分别是2G和2G。
而在user space中,JVM heap +perm 会占用一部分user space,剩下的就是native memory了,当划分了1400M给JVM的heap后,所剩的native memory理论上只有600M了。
并且perm还会占掉一份内存,大概64M,剩下的为600M-64M=546M,而且,理论上要想能读取256M的文件,java heap的最大值应该不小于390M(自己poc过),而os上还运行着
其他的用户进程,也在消耗着user space,最后导致由native memory不足引起OOM。

因此,基于OS和hardware(CPU)已经无法改变的前提,需要合理分配JVM的heap最大值,既要兼顾application的使用(heap的-Xmx尽可能大),又要兼顾native memory不被浪费掉(heap的-Xmx尽可能小)。

最后:分给JVM的heap的-Xmx时要合理,不是越大越好,需要针对具体的应用给个合理的值,最好结合GC的策略分析一段时间heap后,给出合理的heap的-Xmx值。

另外注意以下事实:
I、场景一:
JVM分配1595M,提示初始化jvm失败,说明不能从native memory划分1595M的memory
D:\tools\native_memory>java -Xms1595m -Xmx1595m ReadLargeFileUnderExhastedNativeMemory
Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.

但是同样的环境(什么都没有改变,5s钟内)把JVM参数调小1M,可以正常读取27M的文件。
D:\tools\native_memory>java -Xms1594m -Xmx1594m ReadLargeFileUnderExhastedNativeMemory
=fileSize is =27773440=end=
buf ok

但是27M > 1M,怎么还可以读取呢?!

II、场景二:
还有:读取256M大小文件:
D:\tools\native_memory>java -Xms1332m -Xmx1332m ReadLargeFileUnderExhastedNativeMemory
=fileSize is =268435456=end=
buf ok

1338M=1595M-256M > 1333M,需要native memory至少大于256M。

D:\tools\native_memory>java -Xms1333m -Xmx1333m ReadLargeFileUnderExhastedNativeMemory
=fileSize is =268435456=end=
Exception in thread "main" java.lang.OutOfMemoryError
at java.io.FileInputStream.readBytes(Native Method)
at java.io.FileInputStream.read(FileInputStream.java:198)
at ReadLargeFileUnderExhastedNativeMemory.main(ReadLargeFileUnderExhastedNativeMemory.java:22)


除了考虑native memory之外,是否要考虑os的page大小?
********************


VIP:注意:native oom时,除了考虑jvm参数,还需要考虑os的制约参数,

如:

/proc/sys/kernel/pid_max,
/proc/sys/kernel/thread-max,
max_user_process(ulimit -u),
/proc/sys/vm/max_map_count。

可参考《单个JVM下开启100w线程数》
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值