一. 定义
直接内存不属于java虚拟机内存,而属于操作系统内存
当我调用直接内存(Direct Memory)
- Direct Memory
常见于 NIO 操作时,用于数据缓冲区
分配回收成本较高,但读写性能高
不受 JVM 内存回收管理
二. 直接内存的内存溢出
- 演示图:
- 演示代码:
package jvm1;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
public class Demo9 {
static int _100Mb = 1024 * 1024 * 100;
public static void main(String[] args) {
List<ByteBuffer> list = new ArrayList<>();//加入声明周期更长的List集合中
int i = 0;
try {
while (true) {
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(_100Mb);
list.add(byteBuffer);
i++;
}
} finally {
System.out.println(i);
}
// 方法区是jvm规范, jdk6 中对方法区的实现称为永久代
// jdk8 对方法区的实现称为元空间
}
}
三. 直接内存的释放原理
案例1
- 分析1
- 分析2
- 源码分析:
- 垃圾回收GC分析:
-XX:+DisableExplicitGC 禁用显式的垃圾回收
- 原代码:
package jvm1;
import java.io.IOException;
import java.nio.ByteBuffer;
/*
禁用显式回收对直接内存的影响
*/
public class Demo10 {
static int _1Gb = 1024 * 1024 * 1024;
/*
* -XX:+DisableExplicitGC 显式的
*/
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();
}
}
案例2:
- 分析1
- 原代码:
package jvm1;
import sun.misc.Unsafe;
import java.io.IOException;
import java.lang.reflect.Field;
/*
直接内存分配的底层原理:Unsafe
*/
public class Demo11 {
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);
}
}
}
根据案例1和案例2的总结:
- 分配和回收原理
使用了 Unsafe 对象完成直接内存的分配回收,并且回收需要主动调用 freeMemory 方法
ByteBuffer 的实现类内部,使用了 Cleaner (虚引用)来监测 ByteBuffer 对象,一旦ByteBuffer 对象被垃圾回收,那么就会由 ReferenceHandler 线程通过 Cleaner 的 clean 方法调用 freeMemory 来释放直接内存