JVM学习笔记——本机直接内存溢出

一、JVM直接内存

直接内存并不是虚拟机运行时数据区的一部分,也不是Java 虚拟机规范中定义的内存区域。在JDK1.4 中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的 I/O 方式,它可以使用 native 函数库直接分配堆外内存,然后通过一个存储在Java堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆中来回复制数据。

  • 本机直接内存的分配不会受到Java 堆大小的限制,受到本机总内存大小限制
  • 直接内存也可以由 -XX:MaxDirectMemorySize 指定
  • 直接内存申请空间耗费更高的性能
  • 直接内存IO读写的性能要优于普通的堆内存

当我们的需要频繁访问大的内存而不是申请和释放空间时,通过使用直接内存可以提高性能。

二、直接内存溢出测试

测试代码如下,运行时添加参数 -Xmx20M -XX:MaxDirectMemorySize=10M 设置降低直接内存的空间来加快异常的抛出

package test_DirectMemoryOOM;

import java.lang.reflect.Field;
import sun.misc.Unsafe;

public class DirectrMemoryOOM {
    private static final int _1M = 1024 * 1024;
    
    public static void main(String[] args) throws Exception {
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        @SuppressWarnings("restriction")
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        while(true) {
            unsafe.allocateMemory(_1M);
        }
    }

}

对于在eclipse上,使用sun.misc.Unsafe会出现找不到类的报错,这是出于安全考虑做的限制。可以通过以下方法解决:

Project > properties > Java Compilee > Errors/Warnings :

eclipse配置.png

运行结果:

Exception in thread "main" java.lang.OutOfMemoryError
   at sun.misc.Unsafe.allocateMemory(Native Method)
   at test_DirectMemoryOOM.DirectrMemoryOOM.main(DirectrMemoryOOM.java:15)

不断申请1M的空间,最终会耗尽内存抛出 OutOfMemoryError 异常。

三、注意

由于申请直接内存不由虚拟机管理,所以由此导致的 OOM 是不会在 Heap Dump 文件中看出明显的异常。当 OOM 后发现 Dump 文件很小同时程序直接或间接使用了 NIO ,就可以考虑一下这方面的原因。

关于 Heap Dump 的内容可以在 JVM学习笔记——jhat的使用 了解

你可能感兴趣的:(JVM学习笔记——本机直接内存溢出)