这篇文章要从一个奇怪的注释说起,就是下面这张图:
我们可以不用管具体的代码逻辑,只是单单看这个 for 循环。
在循环里面,专门有个变量 j,来记录当前循环次数。
第一次循环以及往后每 1000 次循环之后,进入一个 if 逻辑。
在这个 if 逻辑之上,标注了一个注释:prevent gc.
prevent,这个单词如果不认识的同学记一下,考试肯定要考的:
这个注释翻译一下就是:防止 GC 线程进行垃圾回收。
具体的实现逻辑是这样的:
核心逻辑其实就是这样一行代码:
Thread.sleep(0);
这样就能实现 prevent gc 了?
懵逼吗?
懵逼就对了,懵逼就说明值得把玩把玩。
这个代码片段,其实是出自 RocketMQ 的源码:
org.apache.rocketmq.store.logfile.DefaultMappedFile#warmMappedFile
事先需要说明的是,我并没有找到写这个代码的人问他的意图是什么,所以我只有基于自己的理解去推测他的意图。如果推测的不对,还请多多指教。
虽然这是 RocketMQ 的源码,但是基于我的理解,这个小技巧和 RocketMQ 框架没有任何关系,完全可以脱离于框架存在。
我给出的修改意见是这样的:
把 int 修改为 long,然后就可以直接把 for 循环里面的 if 逻辑删除掉了。
这样一看是不是更加懵逼了?
不要慌,接下来,我给你抽丝剥个茧。
另外,在“剥茧”之前,我先说一下结论:
- 提出这个修改方案的理论立足点是 Java 的安全点相关的知识,也就是 safepoint。
- 官方最后没有采纳这个修改方案。
- 官方采没采纳不重要,重要的是我高低得给你“剥个茧”。
探索
当我知道这个代码片段是属于 RocketMQ 的时候,我想到的第一个点就是从代码提交记录中寻找答案。
看提交者是否在提交代码的时候说明了自己的意图。
于是我把代码拉了下来,一看提交记录是这样的:
我就知道这里不会有答案了。
因为这个类第一次提交的时候就已经包含了这个逻辑,而且对应这次提交的代码也非常多,并没有特别说明对应的功能。
从提交记录上没有获得什么有用的信息。
于是我把目光转向了 github 的 issue,拿着关键词 prevent gc 搜索了一番。
除了第一个链接之外,没有找到什么有用的信息: