一、概念和特征

  • 直接内存并非 JVMS 定义的标准 Java 运行时内存。
  • JDK1.4 加入了新的 NIO 机制,目的是防止 Java 堆 和 Native 堆之间往复的数据复制带来的性能损耗,此后 NIO 可以使用 Native 的方式直接在 Native 堆分配内存。
  • 直接内存区域是全局共享的内存区域。
  • 直接内存区域可以进行自动内存管理(GC),但机制并不完善。
  • 本机的 Native 堆(直接内存) 不受 JVM 堆内存大小限制。
  • 可能出现 OutOfMemoryError 异常。

二、异常演示

测试代码:

 1
 2public class TestNativeHeap {
 3
 4	/**
 5	 * VM Args: -XX:MaxDirectMemorySize=10M
 6	 */
 7
 8	// 每次内存分配大小
 9	private static int _1M =1024*1024;
10
11	public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
12		Field unsafeFiled = Unsafe.class.getFields()[0];
13		unsafeFiled.setAccessible(true);
14		Unsafe unsafe = (Unsafe) unsafeFiled.get(null);
15		while (true) {
16			unsafe.allocateMemory(_1M);
17		}
18	}
19}

以上代码运行会出现 OutOfMemoryError 异常,原因是不断申请内存将超出 Native 堆限制。

直接内存导致的 OutOfMemoryError 异常,在异常信息中不会有明显的堆栈区错误提示;同时另一大特点就是内存转储文件(dump)出来会非常小,如果项目中出现这种情况,并且直接或者间接地使用了 NIO 技术,那么应该考虑是否为直接内存导致的内存溢出。