基础知识
- java中mmap过程如下,最终的mappedByteBuffer实际是一个DirectByteBuffer对象
File file = new File("xxx");
FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel();
MappedByteBuffer mappedByteBuffer = fileChannel.map(MapMode.READ_WRITE, 0, 4096);
- 看一下DirectByteBuffer构建源码,可以看到每一个DirectByteBuffer都会包含一个Cleaner实例(视图viewer没有)

- Cleaner里面是利用的虚引用,当DirectByteBuffer对象被垃圾回收时,会调用构造Cleaner时传入的回调方法,对MappedByteBuffer来说就是执行unmap,具体逻辑在FileChannelImpl的内部类Unmapper。对普通DirectByteBuffer来说就是Deallocator中的unsafe.freeMemory()
- 当我们想要主动释放内存映射时,最简单的办法就是直接调用
((DirectBuffer) mappedByteBuffer).cleaner().clean()
进阶部分
- 后来了解到Cleaner类在java9前后的包是不一样的,所以如果代码里持有Cleaner的对象,就不能在所有jdk中编译了,当然直接调用
((DirectBuffer) mappedByteBuffer).cleaner().clean()
肯定没有问题
java9前:sun.misc.Cleaner
java9后:java.lang.ref.Cleaner
- 联想到netty是直接内存使用大户,看下netty中的做法。netty中有两个类CleanerJava6、CleanerJava9对应不同的jdk版本分别使用


rocket中的做法
- 在rocket中unmap的逻辑如下,也是通过反射调用clean()方法,和我之前就关注的一个同学的博客做法完全一致,希望以后面基 :)

疑惑思考
- 为啥大家都非要用反射来调用clean呢?
((DirectBuffer) mappedByteBuffer).cleaner().clean()
简单粗暴不香吗?还有就是viewed()方法中的viewedBuffer是什么,没看到有这个名字的方法啊?