在內存模型最開始的章節中,咱們畫出了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