性能文章>PhantomReference? 虚引用? OOM?>

PhantomReference? 虚引用? OOM?原创

7157312

背景

关于各种引用参考
https://www.geeksforgeeks.org/types-references-java/
在我之前认知中,虚引用除了自身对象占用内存外,其引用对象referent在不可达时应该是已经被回收,使用示例验证一下
image.png
image.png
实际却不是这样,上面两个样例都是用参数-Xmx50m运行发现使用PhantomReference时会导致OOM,而使用SoftReference是正常运行的。
在确认PhantomReference与SoftReference都没有添加多余字段,也就证明这两个对象除去referent占用内存应该是一致的。

复现

按之前想法,经历一轮gc后PhantomReference所引用的referent对象应该为空[这里不能get()来获取,因为此方法一直会返回null],示例断点验证一下
image.png
image.png
从两个不同示例来看,PhantomReference所引用的referent对象经过一次gc后并不为null,但是在ReferenceQueue队列中存在此对象也就证明ModelSon对象是可回收的。

分析

PhantomReference源码中有一段注释
image.png
说明了PhantomReference和软引用、弱引用不一样的是PhantomReference加入队列后并不会自动被gc清理,也就是需要手动清理。
在gc时都会调用ReferenceProcessor::process_discovered_references方法处理各种引用
image.png
从process_discovered_references实现中可以看到在调用方法process_discovered_reflist软引用和虚引用第三个参数是不一样的,process_discovered_reflist继续往下可以看到第三个参数是clear_referent,这个参数只在process_phase3[并行处理实现是一样的]中有使用此参数,继续往下
image.png
可以看到当clear_referent为false时会将referent对象标记成存活,虽然会进入ReferenceQueue队列,但是referent对象其实还是在内存中的,这就解释了之前使用PhantomReference会导致OOM的问题。

使用

那么PhantomReference到底是怎么用的呢?
有一种用法是代替finalize方法的实现,PhantomReference可以作为一种代替方案。
image.png
image.png

总结

PhantomReference在jvm中只是不影响gc处理,并不代表其不会强引用referent,所以还是需要自己调用clear方法清理对referent对象的强引用。

问题

这里只是对于PhantomReference导致OOM的问题追查,实际上还有很多细节需要了解,列出其中两点

  1. SoftReference为什么修改clock就可以回收软引用[可以查看should_clear_reference的实现和调用方]
  2. 与java.lang.ref.FinalReference的区别是什么

1.关于SoftReference在内存使用很少的情况使其对象回收,可以通过修改SoftReference字段clock为一个比较大的值,在gc的时候触发SoftReference回收
2.关于对象是否被回收验证可以使用hsdb,也可以下载jar执行attach后,使用objectvisit命令查找对象是否存在
https://github.com/RookieZQF/enhance-hsdb/blob/master/lib/clhsdb-enhance-2021-03-jar-with-dependencies.jar
wget https://raw.githubusercontent.com/RookieZQF/enhance-hsdb/master/lib/clhsdb-enhance-2021-03-jar-with-dependencies.jar
image.png

请先登录,再评论

这例好完整。

111月前

我在JDK15上测试了一下,没有这个问题,新版本的JDK应该已经修改了

11年前
回复 maomao:

确实是的

1年前回复

有代码、有场景、有结果、有说明,逻辑清晰、代码完整,如果再配已一些针对虚应用出现的OOM案例就更完美了。毕竟一次OOM的分析需要有参考的场景和环境,可以让大家避免采坑,或者采坑后尽快脱坑。

11年前
回复 Rookie_267692:

嗯~ 确实没遇到过所以想了解,感谢分享🙏

1年前回复
回复 heroyeah_293541:

虚引用导致OOM的具体案例我也没碰到过,很少用到虚引用

1年前回复

为你推荐

不起眼,但是足以让你有收获的JVM内存分析案例
分析 这个问题说白了,就是说有些int[]对象不知道是哪里来的,于是我拿他的例子跑了跑,好像还真有这么回事。点该 dump 文件详情,查看相关的 int[] 数组,点该对象的“被引用对象”,发现所
协助美团kafka团队定位到的一个JVM Crash问题
概述 有挺长一段时间没写技术文章了,正好这两天美团kafka团队有位小伙伴加了我微信,然后咨询了一个JVM crash的问题,大家对crash的问题都比较无奈,因为没有现场,信息量不多,碰到这类问题我
又发现一个导致JVM物理内存消耗大的Bug(已提交Patch)
概述 最近我们公司在帮一个客户查一个JVM的问题(JDK1.8.0_191-b12),发现一个系统老是被OS Kill掉,是内存泄露导致的。在查的过程中,阴差阳错地发现了JVM另外的一个Bug。这个B
JVM实战:优化我的IDEA GC
IDEA是个好东西,可以说是地球上最好的Java开发工具,但是偶尔也会卡顿,仔细想想IDEA也是Java开发的,会不会和GC有关,于是就有了接下来对IDEA的GC进行调优 IDEA默认JVM参数: -
不起眼,但是足以让你收获的JVM内存案例
今天的这个案例我觉得应该会让你涨姿势吧,不管你对JVM有多熟悉,看到这篇文章,应该还是会有点小惊讶的,不过我觉得这个案例我分享出来,是想表达不管多么奇怪的现象请一定要追究下去,会让你慢慢变得强大起来,
如何通过反射获得方法的真实参数名(以及扩展研究)
前段时间,在做一个小的工程时,遇到了需要通过反射获得方法真实参数名的场景,在这里我遇到了一些小小的问题,后来在部门老大的指导下,我解决了这个问题。通过解决这个问题,附带着我了解到了很多新的知识,我觉得
谨防JDK8重复类定义造成的内存泄漏
概述 如今JDK8成了主流,大家都紧锣密鼓地进行着升级,享受着JDK8带来的各种便利,然而有时候升级并没有那么顺利?比如说今天要说的这个问题。我们都知道JDK8在内存模型上最大的改变是,放弃了Perm
JDK13 GA发布:5大特性解读
JDK13 GA版本 5大新特性如下: 350: Dynamic CDS Archives 351: ZGC: Uncommit Unused Memory 353: Reimplement the