获取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堆外内存回收】
经验总结扩展阅读
- 旧事重提为什么要改名为朝花夕拾
- 德人易行是什么公司
- 单反相机的原理
- 豆芽怎么几天不发芽
- 卖瓷砖的利润怎么样
- 区什么工什么的成语
- 和三五有关的成语
- 如何评价迪士尼电影的宣传和营销
- 雨衣属于什么垃圾
- 粽叶是什么植物的叶子