在内存模型最开始的章节中,咱们画出了JVM的内存模型,里面并不包含直接内存,也就是说这块内存区域并非JVM运行时数据区的一部分,但它却会被频繁的使用,缘由是NIO这个包。
java
NIO(New input/output)是JDK1.4中新加入的类,引入了一种基于通道(channel)和缓冲区(buffer)的I/O方式,它可使用Native函数库直接分配堆外内存,而后经过堆上的DirectByteBuffer对象对这块内存进行引用和操做。jvm
能够看出,直接内存的大小并不受到java堆大小的限制,甚至不受到JVM进程内存大小的限制。它只受限于本机总内存(RAM及SWAP区或者分页文件)大小以及处理器寻址空间的限制(最多见的就是32位/64位CPU的最大寻址空间限制不一样)。
函数
直接内存出现OutOfMemoryError的缘由是对该区域进行内存分配时,其内存与其余内存加起来超过最大物理内存限制(包括物理的和操做系统级的限制),从而致使OutOfMemoryError。另外,若咱们经过参数“-XX:MaxDirectMemorySize”指定了直接内存的最大值,其超过指定的最大值时,也会抛出内存溢出异常。
spa
1 /** 2 * jvm直接内存溢出 3 * JVM参数:-Xmx20M -XX:MaxDirectMemorySize=10M 4 * Created by chenjunyi on 2018/4/26. 5 */ 6 public class DirectMemoryOOM { 7 8 private static final int _1MB = 1024 * 1024; 9 10 public static void main(String[] args) throws IllegalAccessException { 11 //经过反射获取Unsafe类并经过其分配直接内存 12 Field unsafeField = Unsafe.class.getDeclaredFields()[0]; 13 unsafeField.setAccessible(true); 14 Unsafe unsafe = (Unsafe) unsafeField.get(null); 15 while (true) { 16 unsafe.allocateMemory(_1MB); 17 } 18 } 19 20 }
结果以下,能够看出,其抛出的内存溢出异常并无指定是JVM那一块数据区域:操作系统
1 Exception in thread "main" java.lang.OutOfMemoryError 2 at sun.misc.Unsafe.allocateMemory(Native Method) 3 at com.manayi.study.jvm.chapter2._07_DirectMemoryOOM.main(_07_DirectMemoryOOM.java:22)
上面的例子有点特殊,由于咱们使用到了Unsafe这个类(这个类为何经过反射进行获取先不讨论),它的allocateMemory方法可以直接从堆外内存中申请内存(类比于c的malloc函数)。不一样于DirectByteBuffer的内存分配方式(先计算是否有足够的可用内存再决定是手动抛异常仍是向操做系统申请分配内存),Unsafe是直接向操做系统申请分配内存,若未申请到则抛异常。code