一道面试题引发的对Java内存模型的一点疑问
问题描述
如上图所示程序,按道理,子线程会通过 num 操作破坏 while 循环的条件,从而终止循环,执行最后的输出操作。但在我的多次运行中,偶尔会出现 while 循环一直不结束的场合。像我截图一样,程序一直不终止,JDK7、JDK8 均已试验,均能偶然触发。
回复
[西湖の风]:变量前加个 volatile。
[csyangchsh]:volatile 使用读写屏障强制刷新缓存,如果不加就由 CPU 决定何时刷新。
[sofkyle]:由 CPU 决定何时刷新,那么可以认为,终会有一个时机会去刷新,但是while卡在那一直不刷新。
[你假笨]:和 jit 也是有一定关系的,-Xint 设定解释执行,也可以只关闭 OSR 看看,-XX:-UseOnStackReplacement。
JVM STW 里的 no vm operation 是怎么发生的
问题描述我们线上应用提供的服务接口突然超时(dubbo服务接口调用耗时最大限制1s),发现gc.log在对应的时间进入了STW,耗时1.526s查看对应的vm.log发现在相对饮的时间有一个no vm operation提示,请教下:no vm operation,这个类型vm具体在做什么操作啊?如何优化?
回复
[你假笨]:safepoint并不是一定要发生了某个VMOP才会进入的,VMThread本身的执行,就是不断循环,看是否有必要进入safepoint,或者是否要执行一些VMOP,可以看下这块代码。
while (!should_terminate() && _cur_vm_operation == NULL) {
// wait with a timeout to guarantee safepoints at regular intervals
bool timedout =
VMOperationQueue_lock->wait(Mutex::_no_safepoint_check_flag,
GuaranteedSafepointInterval);
// Support for self destruction
if ((SelfDestructTimer != 0) && !is_error_reported() &&
(os::elapsedTime() > SelfDestructTimer * 60)) {
tty->print_cr("VM self-destructed");
exit(-1);
}
if (timedout && (SafepointALot ||
SafepointSynchronize::is_cleanup_needed())) {
MutexUnlockerEx mul(VMOperationQueue_lock,
Mutex::_no_safepoint_check_flag);
// Force a safepoint since we have not had one for at least
// 'GuaranteedSafepointInterval' milliseconds. This will run all
// the clean-up processing that needs to be done regularly at a
// safepoint
SafepointSynchronize::begin();
#ifdef ASSERT
if (GCALotAtAllSafepoints) InterfaceSupport::check_gc_alot();
#endif
SafepointSynchronize::end();
}
_cur_vm_operation = _vm_queue->remove_next();
// If we are at a safepoint we will evaluate all the operations that
// follow that also require a safepoint
if (_cur_vm_operation != NULL &&
_cur_vm_operation->evaluate_at_safepoint()) {
safepoint_ops = _vm_queue->drain_at_safepoint_priority();
}
}
几个关键的点,GuaranteedSafepointInterval,timedout,SafepointSynchronize::iscleanupneeded()如果上面条件满足,就会发生 no vm operation 的 safepoint 操作。
通过GarbageCollectorMXBean获取到的fgc次数耗时与jstat获取到的不一致
问题描述
-XX: UseCompressedOops -Xms5g -Xmx5g -XX:PermSize=256M -XX:MaxPermSize=1024m -XX:NewSize=3g -XX:MaxNewSize=3g -XX: UseCMSInitiatingOccupancyOnly -XX: PerfDataSaveToFile -XX:SurvivorRatio=10 -Xloggc:/data/dataLogs/gc/gc.log -verbose:gc -XX: PrintGCDateStamps -XX: PrintGCDetails -XX: UseConcMarkSweepGC -XX: UseCMSCompactAtFullCollection -XX: CMSClassUnloadingEnabled -XX: DisableExplicitGC -XX:CMSInitiatingOccupancyFraction=80 -XX: HeapDumpOnOutOfMemoryError
如题,这是我的 jvm 参数,jstat采集到的ygc次数与mxbean是一致的,fgc的数量大概是mxbean统计到的两倍,但是不到两倍。
对于耗时,jstat采集到的无论是ygc还是fgc均小于mxbean统计到的数据。
回复
[Rookie_267692]:这是因为CMS收集器在MXBean是在每次发生FGC时只会在Sweeping统计一次,而jstat会在InitialMark阶段统计一次,FinalMark阶段统计一次,这样发生一次CMS gc时就会统计两次,所以次数不一致。gc时间在MXBen中统计的是整个gc从开始到结束时间,jstat统计的是gc在每个阶段实际耗费的时间。
推荐阅读 ZGC什么时候会进行垃圾回收
推荐阅读 GC一些长时间停顿问题排查及解决办法