RocketMQ Intrinsic会导致应用卡顿吗?
RocketMQ 是阿里巴巴开源的MQ产品,使用非常广泛,里面有个函数叫“warmMappedFile”,指的是RocketMQ是通过warmMapped机制内存映射磁盘去做IO,在申请完一块磁盘映射的内存以后,会去做预热。 这里有for循环“for (int i = 0, j = 0; i < this.fileSize”,每隔一个PACG_SIZE去“byteBuffer.put(i, (byte) 0)”;,这样的话,操作系统就会发生缺页,把内存真正分配出来,而不只是EMV数据结构。分配出来以后,等到程序真正使用这块内存的时候,就是纯内存IO,不太会触发这种缺页了,可以变得更快,目的是减少程序卡顿。
但是后面加了if这一段,可以想到刚开始这个循环有问题,因为 byteBuffer.put是Intrinsic,最底层是Intrinsic,方法返回的时候,没有方法调用。JVM在方法返回以及循环末尾检查,是否有Safepoints,来看是否要进入GC,但是因为这是一个Intrinsic,所以没有到检查点,同样这是一个CountedLoop,也没法去进入检查点。因为JVM有个机制,如果这是一个 int作为index去Counted次数的话,为了性能是不会去检查,因为它认为这是有限次的循环,所以不用检查次数。 这种机制循环里面非常简单,中间有可能因为操作系统原因带来卡顿,导致循环,基本上没法进入GC,因为线程没有进入Safepoints,整个界面都没法进入GC, 夯住很长时间,当时大家觉得很不可思议,但是通过一个很简单方法修好了,就是每隔1000字循环的时候,去调一个“Thread.sleep(0)”。 刚刚提到,“byteBuffer.put”没法出发,Thread.sleep是个JNI,返回的时候会检查Safepoints,所以就可以让这个程序能够进入到Safepoints,这个代码就不会影响JVM进入到GC了,代码目前还可以从开源软件上看到。
“-XX:+UseCountedLoopSafepoints”
解决这个问题,还有另一种方式,通过一个选项叫“-XX:+UseCountedLoopSafepoints”,可以JVM自动在CountedLoop结尾检查这Safepoints,当然这带来的副作用是,CountedLoop末尾都会检查Safepoints,这样就会影响整体性能。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。