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

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线程数》

猜你喜欢

转载自can-do.iteye.com/blog/2250704
今日推荐