![40c3f4a8c8294fed605c8be3ee47d915.png](https://i-blog.csdnimg.cn/blog_migrate/576a4b5d5180c263c5386210b346a5c3.jpeg)
一道面试题引发的对Java内存模型的一点疑问
问题描述
![f422eee25d14eab061693decaadb2b8d.png](https://i-blog.csdnimg.cn/blog_migrate/d77d52935f750ce8fb140050f33aa677.png)
如上图所示程序,按道理,子线程会通过 num++ 操作破坏 while 循环的条件,从而终止循环,执行最后的输出操作。但在我的多次运行中,偶尔会出现 while 循环一直不结束的场合。像我截图一样,程序一直不终止,JDK7、JDK8 均已试验,均能偶然触发。
回复
[西湖の风]:变量前加个 volatile。
[csyangchsh]:volatile 使用读写屏障强制刷新缓存,如果不加就由 CPU 决定何时刷新。
[sofkyle]:由 CPU 决定何时刷新,那么可以认为,终会有一个时机会去刷新,但是while卡在那一直不刷新。
[你假笨]:和 jit 也是有一定关系的,-Xint 设定解释执行,也可以只关闭 OSR 看看,-XX:-UseOnStackReplacement。
JVM STW 里的 no vm operation 是怎么发生的
问题描述
![c841d882b56992fc1d3c47193afdf751.png](https://i-blog.csdnimg.cn/blog_migrate/03bee4772454caada0dda14db0b07d56.jpeg)
我们线上应用提供的服务接口突然超时(dubbo服务接口调用耗时最大限制1s),发现gc.log在对应的时间进入了STW,耗时1.526s查看对应的vm.log发现在相对饮的时间有一个no vm operation提示,请教下:no vm operation,这个类型vm具体在做什么操作啊?如何优化?
回复
[你假笨]:safepoint并不是一定要发生了某个VM_OP才会进入的,VMThread本身的执行,就是不断循环,看是否有必要进入safepoint,或者是否要执行一些VM_OP,可以看下这块代码。
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::is_cleanup_needed()
如果上面条件满足,就会发生 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在每个阶段实际耗费的时间。
![979d9c9e17bf4144a661ae152e059300.png](https://i-blog.csdnimg.cn/blog_migrate/8d62980e85e337e6e03ba0bd9803e5fe.jpeg)
欢迎到 PerfMa 社区 参与上述问题讨论~
推荐阅读:
JVM源码分析之警惕存在内存泄漏风险的FinalReference(增强版) | PerfMa应用性能技术社区club.perfma.com![278817260002c9625cf3d0a8712908cb.png](https://i-blog.csdnimg.cn/blog_migrate/5acc09dead17b1401df45a066525a30d.jpeg)
![1045096e64f45101668cbdac7cf1c316.png](https://i-blog.csdnimg.cn/blog_migrate/24c817c0a791feb86f7e65007afff5b5.jpeg)