JVM除了堆內存、棧內存,還有DirectMemory內存,DirectMemory是java nio引入的。
在JDK1.4中新加入了NIO(New INput/Output)類,引入了一種基於通道(Channel)與緩沖區(Buffer)的I/O方式,它可以使用Native函數庫直接分配堆外內存,
然后通過一個存儲在Java堆中的DirectByteBuffer對象作為這塊內存的引用進行操作。這樣能在一些場景中顯著提高性能,因此避免了在Java堆和Native堆中來回復制數據。
Direct Memory是受GC控制的,例如ByteBuffer bb = ByteBuffer.allocateDirect(1024),這段代碼的執行會在堆外占用1k的內存,Java堆內只會占用一個對象的指針引用的大小,堆外的這1k的空間只有當bb對象被回收時,才會被回收,這里會發現一個明顯的不對稱現象,就是堆外可能占用了很多,而堆內沒占用多少,導致還沒觸發GC,那就很容易出現Direct Memory造成物理內存耗光。
垃圾收集進行時,虛擬機雖然會對Direct Memory進行回收,但是Direct Memory卻不能像新生代、老年代那樣,發現空間不足了就通知收集器進行垃圾回收,它只能等待老年代滿了后Full GC,然后順便棒它清理內存的廢棄對象。否則它只能一直等到拋出內存異常時,先catch掉,再在catch塊里System.gc()。
可通過-XX:MaxDirectMemorySize調整大小,內存不足時拋出OutOfMemoryError或者OutOfMemoryError:Direct buffer mempry