大家好,我是喜欢呆在家7天的歪歪。这篇文章开头有个奇怪的评论,就是下图:具体的代码逻辑我们可以忽略,只看for循环。在循环中,有一个特殊的变量j,用来记录当前的循环次数。在第一个循环和此后每1000个循环之后,输入一个if逻辑。在这个if逻辑之上,标注了一条注释:preventgc.prevent。如果你不会这个词,记住它,你肯定要考试:这个注释翻译过来就是:防止GC线程进行垃圾回收。具体实现逻辑如下:核心逻辑其实就是这么一行代码:Thread.sleep(0);这样preventgc可以实现吗?使困惑?不懂事就对了,懂事就值得玩。这段代码片段其实是来自RocketMQ的源码:org.apache.rocketmq.store.logfile.DefaultMappedFile#warmMappedFile需要提前说明的是,我没有找到写这段代码的人,问一下他的用意是什么,所以我只需要根据自己的理解来推断他的意图。如果猜错了,请指教。虽然这是RocketMQ的源码,但根据我的理解,这个小技巧与RocketMQ框架无关,可以脱离框架存在。我给的修改是这样的:把int改成long,然后for循环里面的if逻辑就可以直接去掉了。这不是让你更迷茫吗?别慌,接下来,我给你抽茧。另外,在“抽丝剥茧”之前,我先做一个总结:提出这个修改方案的理论依据是Java的安全点相关的知识,即safepoint。官方最终没有采纳这个修正案。正式采纳与否并不重要,重要的是我给你“剥茧”。探索当知道这段代码属于RocketMQ时,我第一时间想到的就是从代码提交记录中寻找答案。看提交者在提交代码时是否表明了自己的意图。于是我把代码拉下来,看到commit记录是这样的:我就知道这里不会有答案。因为这个类在第一次提交的时候就已经包含了这个逻辑,而且这次提交对应的代码也很多,并没有具体说明对应的功能。没有从提交日志中获得有用的信息。于是把目光转向了github的issue,搜索关键词preventgc。除了第一个链接,没有找到有用的信息:第一个链接对应的issues是这个:https://github.com/apache/roc...这个issue其实就是我们针对这个issue所讨论的whatwasproposed过程中就是之前出现的修改方案:也就是说,我想通过源码或者github找到这个问题的权威答案,但是没有找到。于是我又去了这个神奇的网站,发现了这个2018年提出的问题:https://stackoverflow.com/que...问题和我们的一模一样,不过这里是这个问题的答案:thisTheanswer不好,因为我觉得这个答案不对,不过没关系,我可以直接以这个答案为出发点,对齐差点,赋能。看这个回答的第一句话:Itdoesnot(它没有)。问题来了:“它”是谁?“没有什么?”指的是之前出现的代码,“No”表示没有阻止GC线程进行垃圾回收,这个回答说:调用Thread.sleep(0)的目的是为了给GC线程有机会被操作系统选择执行垃圾清理。它的副作用是可能会更频繁地运行GC,毕竟你每1000次迭代就有机会运行GC,但好处是它可以防止longgarbagecollections.换句话说,这段代码是想“触发”GC,而不是“避免”GC,或者“避免”耗时较长的GC。从这个角度来看,程序中的注释实际上是在撒谎或不完整。它不是防止gc,而是对gc采用“分手运行,削峰填谷”的思想,从而防止长时间gc。但是你想想,我们自己编程的时候,一般情况下,“这个地方应该触发GC”的想法永远不会冒出来吧?因为我们知道,对于Java程序员来说,虚拟机是有自己的GC机制的。我们不需要像编写C或C++那样自己管理内存。我们只需要关注业务代码,不需要特别关注GC机制。那么本文最关键的问题来了:为什么要在此处的代码中特别关注GC,并想尝试“触发”GC?先说答案:safepoint,安全点。关于安全点的描述,可以看《深入理解JVM虚拟机(第三版)》的3.4.2节:注意书中的描述:设置了安全点后,判断用户程序在任何位置都没有执行代码指令流。执行必须到达安全点才能暂停,而不是能够暂停以启动垃圾收集。也就是说:没有到达安全点,就不能进行STW,所以可以进行GC。如果在你的认知中,GC线程是可以随时运行的。那么你需要刷新你的理解。接下来,让我们将注意力转向本书的第5.2.8节:SafepointsCausedLongPauses。里面有这么一段话:划线的部分我单独拿出来,大家可以仔细阅读:为了避免安全点过多造成的负担过重,HotSpot虚拟机还有一个循环的优化措施,认为循环次数比较少。如果小于,则执行时间不宜过长,这样使用int类型或范围更小的数据类型作为索引值的循环,默认不会放在安全点。这种循环称为可数循环(CountedLoop)。相应地,使用long或更大数据类型作为索引值的循环称为未计数循环(UncountedLoop),将被放在安全的地方。.意味着在可数循环(CountedLoop)的情况下,HotSpot虚拟机做了一个优化,即直到循环结束,线程才会进入安全点。反之,如果循环没有结束,线程就不会进入安全点,GC线程就必须等待当前线程循环结束进入安全点,才能开始工作。什么是可数循环(CountedLoop)?书中的案例来自这个链接:https://juejin.cn/post/684490...HBase实战:记一次因为Safepoint导致长STW的踩坑之旅如果有时间,我建议你把这个case完整看一下,我只截取解题部分:截图中的while(i
