• DirectByteBuffer中的address指向的地址空间属于堆外内存,它是不受JVM的管控,所以需要我们自己去管理;
  • 前面的文章我们分析过address的地址由mmap或malloc的分配,那么其实DirectByteBuffer回收也是分为两处;

回收malloc分配的内存

当我们直接调用如下代码创建DirectByteBuffer,其内部的address由malloc分配(如果平台支持直接内存)

ByteBuffer.allocateDirect(1024)
复制代码

构造方法

DirectByteBuffer(int cap) {                   // package-privatesuper(-1, 0, cap, cap);boolean pa = VM.isDirectMemoryPageAligned();int ps = Bits.pageSize();long size = Math.max(1L, (long)cap + (pa ? ps : 0));Bits.reserveMemory(size, cap);long base = 0;try {base = unsafe.allocateMemory(size);} catch (OutOfMemoryError x) {Bits.unreserveMemory(size, cap);throw x;}unsafe.setMemory(base, size, (byte) 0);if (pa && (base % ps != 0)) {// Round up to page boundaryaddress = base + ps - (base & (ps - 1));} else {address = base;}cleaner = Cleaner.create(this, new Deallocator(base, size, cap));att = null;
}
复制代码

Cleaner其实是一个虚引用,Deallocator是一个Runnable

public class Cleaner extends PhantomReference<Object>
复制代码

回收的核心原理是虚引用,用于跟踪垃圾回收过程,可以参考我的“Java、Android引用类型”文章。

 private Cleaner(Object referent, Runnable thunk) {super(referent, dummyQueue);this.thunk = thunk;
}
复制代码
  • referent:代表我们创建的DirectByteBuffer;
  • dummyQueue:为Cleaner内部维护的引用队列;
    我们直接看父类Reference
static {ThreadGroup tg = Thread.currentThread().getThreadGroup();for (ThreadGroup tgn = tg;tgn != null;tg = tgn, tgn = tg.getParent());Thread handler = new ReferenceHandler(tg, "Reference Handler");/* If there were a special system-only priority greater than* MAX_PRIORITY, it would be used here*/handler.setPriority(Thread.MAX_PRIORITY);handler.setDaemon(true);handler.start();// provide access in SharedSecretsSharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {@Overridepublic boolean tryHandlePendingReference() {return tryHandlePending(false);}});
}
复制代码

父类静态代码块创建了一个守护线程,当DirectByteBuffer对象从pending状态 ——> enqueue状态时,在handler的run方法中会检测到

 static boolean tryHandlePending(boolean waitForNotify) {Reference<Object> r;Cleaner c;try {synchronized (lock) {if (pending != null) {r = pending;// 'instanceof' might throw OutOfMemoryError sometimes// so do this before un-linking 'r' from the 'pending' chain...c = r instanceof Cleaner ? (Cleaner) r : null;// unlink 'r' from 'pending' chainpending = r.discovered;r.discovered = null;} else {// The waiting on the lock may cause an OutOfMemoryError// because it may try to allocate exception objects.if (waitForNotify) {lock.wait();}// retry if waitedreturn waitForNotify;}}} catch (OutOfMemoryError x) {// Give other threads CPU time so they hopefully drop some live references// and GC reclaims some space.// Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above// persistently throws OOME for some time...Thread.yield();// retryreturn true;} catch (InterruptedException x) {// retryreturn true;}// Fast path for cleanersif (c != null) {c.clean();return true;}ReferenceQueue<? super Object> q = r.queue;if (q != ReferenceQueue.NULL) q.enqueue(r);return true;}
复制代码

如果是c = r instanceof Cleaner ? (Cleaner) r : null;就会得到一个Cleaner,并且调用它的c.clean()方法,

public void clean() {if (!remove(this))return;try {thunk.run();} catch (final Throwable x) {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {if (System.err != null)new Error("Cleaner terminated abnormally", x).printStackTrace();System.exit(1);return null;}});}}
复制代码

clean()方法最终回调用我们初始化时传进来的Deallocator

cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
复制代码

在Deallocator中调用unsafe.freeMemory(address);进行回收

public void run() {if (address == 0) {// Paranoiareturn;}unsafe.freeMemory(address);address = 0;Bits.unreserveMemory(size, capacity);
}
复制代码

回收mmap分配的内存

我们看一次FileChannleImpl中map方法代码

int isize = (int)size;Unmapper um = new Unmapper(addr, mapSize, isize, mfd);if ((!writable) || (imode == MAP_RO)) {return Util.newMappedByteBufferR(isize,addr + pagePosition,mfd,um);} else {return Util.newMappedByteBuffer(isize,addr + pagePosition,mfd,um);}
复制代码

Util.newMappedByteBuffer调用用传入了一个Unmapper实例,Unmapper其实也是一个Runnable,到此其实大家也明白了,最终的回收还是在Unmapper中完成的

public void run() {if (address == 0)return;unmap0(address, size);address = 0;// if this mapping has a valid file descriptor then we close itif (fd.valid()) {try {nd.close(fd);} catch (IOException ignore) {// nothing we can do}}synchronized (Unmapper.class) {count--;totalSize -= size;totalCapacity -= cap;}
}
复制代码

最后调用底层的unmap0来完成内存的回收。

Java零拷贝续——DirectByteBuffer内存回收相关推荐

  1. Java零拷贝四步曲——HeapByteBuffer与DirectByteBuffer

    HeapByteBuffer与DirectByteBuffer Nio中Buffer类继承图如下,其中最主要的类是HeapByteBuffer和DirectByteBuffer HeapByteBuf ...

  2. java transferto_小六六学Netty系列之Java 零拷贝

    前言 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/bin392328206/six-finger种一棵树最好的时间是十年前,其次是现在 我知道很多人不玩qq了 ...

  3. jvm 堆外内存_NIO效率高的原理之零拷贝与直接内存映射

    更多内容,欢迎关注微信公众号:全菜工程师小辉~ 前言 在笔者上一篇博客,详解了NIO,并总结NIO相比BIO的效率要高的三个原因,彻底搞懂NIO效率高的原理. 这篇博客将针对第三个原因,进行更详细的讲 ...

  4. NIO效率高的原理之零拷贝与直接内存映射

    前言 在笔者上一篇博客,详解了NIO,并总结NIO相比BIO的效率要高的三个原因,点击查看. 这篇博客将针对第三个原因,进行更详细的讲解. 首先澄清,零拷贝与内存直接映射并不是Java中独有的概念,并 ...

  5. java 零拷贝详细讲解

    文章目录 一.传统IO 二.零拷贝 1.通过DirectByteBuffer优化 2.通过 linux 2.1 sendFile优化 3.linux 2.4优化 三.java实现零拷贝 1.mmap ...

  6. java具有自动无用内存回收_Java语言程序设计(一)试卷及答案解释

    Java语言程序设计(一)试卷及答案解释 本试卷共6页,满分l00分,考试时间l50分钟. 第一部分选择题 一.单项选择题:本大题共l0小题,每小题l分,共10分.在每小题列出的备选项中只有一项是最符 ...

  7. 操作系统中的零拷贝与java中的使用

    下面是在Linux操作系统中将磁盘中的数据传输到网络设备上的示例图. 在图中可以看到数据先从磁盘上读取到用户空间而后再从用户空间写入到网络设备中,写入和读取一共经历四次拷贝,和四次状态的切换(用户到内 ...

  8. java垃圾回收菜鸟_java程序员不懂JVM内存回收,两年后也是个菜鸟

    java程序员不懂JVM内存回收,两年后也是个菜鸟 在学java程序员的时候,如果你还不懂JVM内存回收,那么你就只能是个很一般的程序员菜鸟了,那么什么是JVM内存回收呢?今天我们就来学习,都还不深入 ...

  9. 计算机IO系列「一」零拷贝技术

    深入剖析Linux IO原理和几种零拷贝机制的实现 转载自:深入剖析Linux IO原理和几种零拷贝机制的实现 - 知乎 前言 零拷贝(Zero-copy)技术指在计算机执行操作时,CPU 不需要先将 ...

最新文章

  1. 认识计算机ppt课件游戏,认识计算机)ppt课件
  2. 怎样用c语言写高速超速罚款标准,pta高速公路超速处罚(C语言)
  3. 深圳一普通中学老师工资单曝光,秒杀程序员,网友:真酸~
  4. Boost:宏BOOST_ASSERT的使用实例
  5. 2018-2019-2 20189215 《网络攻防技术》第九周作业
  6. 使用commons httpclient请求https协议的webservice
  7. 接口的显式实现与隐式实现
  8. 东大OJ-1544: GG的战争法则
  9. 清除stoped impdp/expdp job的方法
  10. kubernetes CKA题库(附答案、视频)
  11. 一个07年毕业研究生的坎坷经历(上)
  12. 重新认识java(五) ---- 面向对象之多态(向上转型与向下转型)
  13. CountDownLatch 用法和源码解析
  14. js实现图片裁剪效果
  15. 吴恩达机器学习6:模型描述
  16. 哈工大软件构造期末复习1
  17. VAE+TSNE-mnist可视化项目
  18. 上期技术综合交易平台[CTP]
  19. python文件目录管理 项目_Python入门教程完整版(懂中文就能学会)
  20. 计算机毕业设计JAVA基金会系统网站mybatis+源码+调试部署+系统+数据库+lw

热门文章

  1. Android View体系(六)从源码解析Activity的构成
  2. Socket网络协议之二
  3. ClewareControl 2.4 发布,传感器控制程序,增加对 python 的支持
  4. 以后教育孩子学好数学的方法 多思动漫数学
  5. Rose VS PowerDesigner
  6. Oracle时间函数
  7. 【Thread】- ReentrantLock、ReentrantReadWriteLock
  8. 如何更好的创建Java对象
  9. DELL R710做Raid显示灰色
  10. SpringMVC+Hibernate+Junit4+json基本框架近乎0配置