reserveMemory内存清理最开始在DirectByteBuffer的构造函数中看到申请内存之前会调用Bits的reserveMemory
方法,如果没有足够的内存,它会从SharedSecrets
获取JavaLangRefAccess
对象进行一些处理,由前面的内容可知 , Reference
中的静态方法启动ReferenceHandler
之后,创建了JavaLangRefAccess
并设置到SharedSecrets
中,所以这里调用JavaLangRefAccess
的tryHandlePendingReference
实际上依旧调用的是Reference
中的tryHandlePending
方法 。
在调用Reference
中的tryHandlePending
方法处理需要回收的对象之后,调用tryReserveMemory
方法判断是否有足够的内存 , 如果内存依旧不够,会调用` System.gc()触发垃圾回收,然后开启一个循环,处理逻辑如下:
- 判断内存是否充足,如果充足直接返回;
- 判断睡眠次数是否小于限定的最大值,如果小于继续下一步 , 否则终止循环;
- 调用tryHandlePendingReference处理penging列表中的引用对象,前面在处理pending列表的逻辑中可以知道 , 如果pending列表不为空 , 会返回true,tryHandlePendingReference也会返回true,此时意味着清理了一部分对象,所以重新进入到第1步进行检查;
如果pending列表为空 , 会返回参数中传入的waitForNotify的值 , 从JavaLangRefAccess的tryHandlePendingReference中可以看出这里传入的是false , 所以会进行如下处理:
- 通过
Thread.sleep(sleepTime)
让当前线程睡眠一段时间 , 这样可以避免reserveMemory方法一直在占用资源; - 对睡眠次数加1;
- 通过
- 如果以上步骤处理之后还没有足够的空间会抛出抛出OutOfMemoryError异常;
class Bits {static void reserveMemory(long size, int cap) {if (!memoryLimitSet && VM.isBooted()) {maxMemory = VM.maxDirectMemory();memoryLimitSet = true;}// 是否有足够内存if (tryReserveMemory(size, cap)) {return;}// 获取JavaLangRefAccessfinal JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();// 调用tryHandlePendingReferencewhile (jlra.tryHandlePendingReference()) {// 判断是否有足够的内存if (tryReserveMemory(size, cap)) {return;}}// 调用gc进行垃圾回收System.gc();boolean interrupted = false;try {long sleepTime = 1;int sleeps = 0;// 开启循环while (true) {// 是否有足够内存if (tryReserveMemory(size, cap)) {return;}// 如果次数小于最大限定次数,终止if (sleeps >= MAX_SLEEPS) {break;}// 再次处理penging列表中的对象if (!jlra.tryHandlePendingReference()) {try {// 睡眠一段时间Thread.sleep(sleepTime);sleepTime <<= 1;sleeps++; // 睡眠次数增加1} catch (InterruptedException e) {interrupted = true;}}}// 抛出OutOfMemoryError异常throw new OutOfMemoryError("Direct buffer memory");} finally {if (interrupted) {// don't swallow interruptsThread.currentThread().interrupt();}}}}public abstract class Reference<T> {static {// ...// 这里设置了JavaLangRefAccessSharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {@Overridepublic boolean tryHandlePendingReference() {// 调用tryHandlePending,这里waitForNotify参数传入的是falsereturn tryHandlePending(false);}});}}
参考Reference源码解析
一文读懂java中的Reference和引用类型
Java 源码剖析——彻底搞懂 Reference 和 ReferenceQueue
【【Java】 DirectByteBuffer堆外内存回收】
推荐阅读
- 怎么删除微信好友(一键恢复已删除好友)
- 浅谈-动态路由之OSPF的理解
- Jupyter,Matplotlib,Pandas 【机器学习】利用 Python 进行数据分析的环境配置 Windows
- 奇迹暖暖幽夜魅影怎么搭配
- 摩尔庄园10月28日神奇密码是多少
- 荣耀magic3支持鸿蒙系统吗_荣耀magic3能升级鸿蒙吗
- 可持久化数组 P3919 【模板】可持久化线段树 1
- 斗罗大陆武魂觉醒荒野行纪2
- 祖玛阁5去6怎么走(祖玛阁杂货店到6层怎么走)
- 【nginx】使用 nginx 时,使用 sub_filter 注入 js 代码,例如 google analysis 等