一道面試題引起的對 Java 內存模型的一點疑問

一道面試題引起的對Java內存模型的一點疑問

問題描述
file面試

如上圖所示程序,按道理,子線程會經過 num++ 操做破壞 while 循環的條件,從而終止循環,執行最後的輸出操做。但在個人屢次運行中,偶爾會出現 while 循環一直不結束的場合。像我截圖同樣,程序一直不終止,JDK七、JDK8 均已試驗,均能偶然觸發。

回覆segmentfault

[西湖の風]:變量前加個 volatile。緩存

[csyangchsh]:volatile 使用讀寫屏障強制刷新緩存,若是不加就由 CPU 決定什麼時候刷新。jvm

[sofkyle]:由 CPU 決定什麼時候刷新,那麼能夠認爲,終會有一個時機會去刷新,可是while卡在那一直不刷新。優化

[你假笨]:和 jit 也是有必定關係的,-Xint 設定解釋執行,也能夠只關閉 OSR 看看,-XX:-UseOnStackReplacement。ui

JVM STW 裏的 no vm operation 是怎麼發生的

問題描述
file
咱們線上應用提供的服務接口忽然超時(dubbo服務接口調用耗時最大限制1s),發現gc.log在對應的時間進入了STW,耗時1.526s查看對應的vm.log發如今相對飲的時間有一個no vm operation提示,請教下:no vm operation,這個類型vm具體在作什麼操做啊?如何優化?lua

回覆spa

[你假笨]: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 操做。code

經過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在每一個階段實際耗費的時間。
file

推薦閱讀 ZGC何時會進行垃圾回收
推薦閱讀 GC一些長時間停頓問題排查及解決辦法
相關文章
相關標籤/搜索