一救鲤、JVM直接內存
直接內存并不是虛擬機運行時數據區(qū)的一部分洋幻,也不是Java 虛擬機規(guī)范中定義的內存區(qū)域蛹锰。在JDK1.4 中新加入了NIO(New Input/Output)類搁料,引入了一種基于通道(Channel)與緩沖區(qū)(Buffer)的 I/O 方式面徽,它可以使用 native 函數庫直接分配堆外內存,然后通過一個存儲在Java堆中的 DirectByteBuffer 對象作為這塊內存的引用進行操作复罐。這樣能在一些場景中顯著提高性能涝登,因為避免了在 Java 堆和 Native 堆中來回復制數據。
- 本機直接內存的分配不會受到Java 堆大小的限制效诅,受到本機總內存大小限制
- 直接內存也可以由 -XX:MaxDirectMemorySize 指定
- 直接內存申請空間耗費更高的性能
- 直接內存IO讀寫的性能要優(yōu)于普通的堆內存
當我們的需要頻繁訪問大的內存而不是申請和釋放空間時胀滚,通過使用直接內存可以提高性能趟济。
二、直接內存溢出測試
測試代碼如下咽笼,運行時添加參數 -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 :
運行結果:
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 后發(fā)現 Dump 文件很小同時程序直接或間接使用了 NIO 素挽,就可以考慮一下這方面的原因。
關于 Heap Dump 的內容可以在 JVM學習筆記——jhat的使用 了解