参考文档:
DirectByteBuffer是java中直接进行堆外内存管理的API,堆外内存可以直接和系统内存进行交互,从而减少一次JVM内存-系统内存之间的交互,提高I/O效率。所以需要学习一下这个类的构造函数、了解背后的设计思想,提高自己对java语言的理解,从而写出更优雅的代码。
1.入口
通过ByteBuffer.allocateDirect方法进行构造
2.DirectByteBuffer的构造函数
2.1 准备内存
2.1.1SharedSecrets类
static void reserveMemory(long size, int cap) {
//初始化maxMemory
if (!memoryLimitSet && VM.isBooted()) {
maxMemory = VM.maxDirectMemory();
memoryLimitSet = true;
}
// 尝试预开辟内存
if (tryReserveMemory(size, cap)) {
return;
}
final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
// 尝试执行Cleaner来释放直接内存,直到内存空间足够
while (jlra.tryHandlePendingReference()) {
if (tryReserveMemory(size, cap)) {
return;
}
}
//系统GC
System.gc();
//间隔轮训尝试开辟内存,轮询时间是1ms的2^
boolean interrupted = false;
try {
long sleepTime = 1;
int sleeps = 0;
while (true) {
if (tryReserveMemory(size, cap)) {
return;
}
if (sleeps >= MAX_SLEEPS) {
break;
}
if (!jlra.tryHandlePendingReference()) {
try {
Thread.sleep(sleepTime);
sleepTime <<= 1;
sleeps++;
} catch (InterruptedException e) {
interrupted = true;
}
}
}
// no luck
throw new OutOfMemoryError("Direct buffer memory");
private static boolean tryReserveMemory(long size, int cap) {
// -XX:MaxDirectMemorySize限制的是总cap,而不是真实的内存使用量,(在页对齐的情况下,真实内存使用量和总cap是不同的)
long totalCap;
while (cap <= maxMemory - (totalCap = totalCapacity.get())) {
if (totalCapacity.compareAndSet(totalCap, totalCap + cap)) {
reservedMemory.addAndGet(size);
count.incrementAndGet();
return true;
}
}
return false;
}
2.2初始化内存
2.3分配内存空间
2.4创建垃圾回收器
2.4.1虚引用
虚引用的概念:无法通过虚引用获取与之关联的实例,当对象被虚引用引用时,发生任何GC的时候,都可以被回收。通常 PhantomReference 与引用队列ReferenceQueue 结合使用,可以实现虚引用关联对象被垃圾回收时能够进行系统通知、资源清理等功能。
当某个被 Cleaner 引用的对象将被回收时,JVM 垃圾收集器会将此对象的引用放入到对象引用pending 链表中,等待Reference-Handler 进行相关处理。其中,Reference-Handler 为一个拥有最高
优先级的守护线程,会循环不断的处理 pending 链表中的对象引用,执行 Cleaner的 clean 方法进行相关清理工作。
Deallocator
Reference类是java引用对象的回收类,他会循环处理被引用的对象,对其进行回收操作