美文网首页
DirectBuffer的释放探究

DirectBuffer的释放探究

作者: 江江的大猪 | 来源:发表于2020-11-23 19:19 被阅读0次

个人认为rocket两个核心技术一个是网络io,一个是文件io。看到MappedByteBuffer的时候对内存映射的释放逻辑产生了疑惑

基础知识

  • 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没有)
image.png
  • Cleaner里面是利用的虚引用,当DirectByteBuffer对象被垃圾回收时,会调用构造Cleaner时传入的回调方法,对MappedByteBuffer来说就是执行unmap,具体逻辑在FileChannelImpl的内部类Unmapper。对普通DirectByteBuffer来说就是Deallocator中的unsafe.freeMemory()

所以根据Cleaner的工作原理就能够理解,为什么网上那么多资料说直接内存会随着gc被回收,有些人甚至在需要主动回收直接内存时直接调用System.gc()

  • 当我们想要主动释放内存映射时,最简单的办法就是直接调用((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版本分别使用

CleanerJava6根据jdk是否有Unsafe类决定通过Unsafe方法还是反射,调用DirectByteBuffer中Cleaner属性的clean()方法

image.png

CleanerJava9直接通过反射调用Unsafe的invokeCleaner()方法(invokeCleaner在java9后才有),内部也是调用的DirectByteBuffer中Cleaner属性的clean()方法

image.png

rocket中的做法

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

疑惑思考

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

相当于用hotspot编译之后再openjdk上运行,就会报错 https://stackoverflow.com/questions/54323645/apache-spark-method-not-found-sun-nio-ch-directbuffer-cleanerlsun-misc-cleaner

相关文章

网友评论

      本文标题:DirectBuffer的释放探究

      本文链接:https://www.haomeiwen.com/subject/iibviktx.html