直接記憶體
定義:
- 常見于 NIO 操作時,用于資料緩沖區
- 配置設定回收成本較高,但讀寫性能高
- 不受 JVM 記憶體回收管理
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
public class memory_overflow {
static int _100Mb = 1024 * 1024 * 100;
public static void main(String[] args) {
List<ByteBuffer> list = new ArrayList<>();
int i = 0;
try {
while (true) {
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(_100Mb);
list.add(byteBuffer);
i++;
}
} finally {
System.out.println(i);
}
}
}
直接記憶體配置設定,每次記憶體配置設定100m,一直配置設定空間,運作代碼會抛出異常 java.lang.OutOfMemoryError: Direct buffer memory , 表示直接記憶體不足。
記憶體的占用 釋放原理
在這裡我們運作一段代碼,給添加一個g的記憶體,之後再進行釋放記憶體,在任務管理器當中進行檢視記憶體的占用情況。使用以下代碼段進行測試
import java.io.IOException;
import java.nio.ByteBuffer;
public class GC_memory {
static int _1Gb = 1024 * 1024 * 1024;
public static void main(String[] args) throws IOException {
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(_1Gb);
System.out.println("配置設定完畢...");
System.in.read();
System.out.println("開始釋放...");
byteBuffer = null;
System.gc(); // 顯式的垃圾回收,Full GC
System.in.read();
}
}
在按壓第一次回車後配置設定記憶體,再一次按壓回車後将記憶體釋放掉。
釋放原理的底層實作
直接記憶體配置設定的底層原理:Unsafe ;
使用了 Unsafe 對象完成直接記憶體的配置設定回收,并且回收需要主動調用 freeMemory 方法
ByteBuffer 的實作類内部,使用了 Cleaner (虛引用)來監測 ByteBuffer 對象,一旦
ByteBuffer 對象被垃圾回收,那麼就會由 ReferenceHandler 線程通過 Cleaner 的 clean 方法調用 freeMemory 來釋放直接記憶體
使用以下代碼段進行示範
package direct;
import sun.misc.Unsafe;
import java.io.IOException;
import java.lang.reflect.Field;
public class GC_memory_bottom {
static int _1Gb = 1024 * 1024 * 1024;
public static void main(String[] args) throws IOException {
Unsafe unsafe = getUnsafe();
// 配置設定記憶體
long base = unsafe.allocateMemory(_1Gb);
unsafe.setMemory(base, _1Gb, (byte) 0);
System.in.read();
// 釋放記憶體
unsafe.freeMemory(base);
System.in.read();
}
public static Unsafe getUnsafe() {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
return unsafe;
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
執行代碼,在任務管理器當中檢視記憶體占用,再配置設定了1g的記憶體後,會上升,記憶體釋放後,又會下降下來。
性能調優
禁用顯示的垃圾回收機制。使用參數 -XX:+DisableExplicitGC 禁用之後直接記憶體的回收會受到影響,在 記憶體的占用 釋放原理 這裡的代碼段進行添加參數。進行測試:
在進行記憶體釋放的時候通常要采用unsafe對象進行釋放