JVM实战 OutOfMemoryError 本机直接内存溢出

本机直接内存–Direct Memory,不是JVM内存中的一部分,但是这部分内存也被频繁的使用,并且可能会产生OutOfMemoryError。

从JDK1.4中新加入了NIO类,引入了基于channel和Buffer的I/O方式,它可以使用Native函数库直接分配堆外内存,也就是在我们系统内存上分配了使用空间,然后使用了Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。为的是提高读写性能。

直接内存可以通过:-XX:MaxDirectMemorySize 来设置大小,如果不设置,默认和堆在最大值-Xmx一样大。

设置本机直接内存的原则就是,各种内存大小+本机直接内存大小<机器物理内存。

代码:

/**
 * www.itzhimei.com
 * 编程技术之美-IT之美
 */
public class DirectMemoryOOM {
    private static final int SIZE_2MB = 1024*1024*2;

    public static void main(String[] args) throws Exception {
        Field uf = Unsafe.class.getDeclaredFields()[0];
        uf.setAccessible(true);
        Unsafe unsafe = (Unsafe)uf.get(null);
        while(true) {
            unsafe.allocateMemory(SIZE_2MB);
        }
    }
}

JVM参数:

-XX:MaxDirectMemorySize=10M

报错如下:

Exception in thread "main" java.lang.OutOfMemoryError
	at sun.misc.Unsafe.allocateMemory(Native Method)
	at com.itzhimei.study.jvm.DirectMemoryOOM.main(DirectMemoryOOM.java:19)

上面的代码可能很多人看不太懂,这一对unsafe是什么意思?怎么就产生直接内存溢出了?

        Field uf = Unsafe.class.getDeclaredFields()[0];
        uf.setAccessible(true);
        Unsafe unsafe = (Unsafe)uf.get(null);
        while(true) {
            unsafe.allocateMemory(SIZE_2MB);
        }

这就要我们大部分程序员并不会用到的Unsafe类。

因为要操作的是JVM之外的内存–直接内存,规范的操作是使用Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作,但是在NIO出现之前,操作直接内存,用的就是Unsafe类。

Unsafe类是什么?

Unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力,同时也带来了指针的问题。过度的使用Unsafe类会使得出错的几率变大,因此Java官方并不建议使用的,官方文档也几乎没有。

知道了Unsafe的能力,所以上面的代码就实现直接内存的使用。也就最终导致直接内存溢出。

更多Unsafe请参考:https://blog.csdn.net/yjaspire/article/details/85248853

内容学习自周志明老师的《深入理解Java虚拟机》