gc-roots-reachability-analysis-savepoint 整理

savepoint, gc roots

  • 對象是否已死?

    • 引用計數(shù)
      • 解決不了循環(huán)引用問題
    • 可達性分析(從 gc roots搜索引用路徑)
      • 虛擬機棧(棧幀中的本地變量表)中的-引用對象
      • 本地方法棧中-JNI(native方法)引用的對象
      • 方法區(qū)中-類靜態(tài)屬性引用的對象
      • 方法區(qū)中-常量引用的對象
    • 引用(上面可達性分析都涉及到了引用)
      • strong reference
      • soft reference
        • 將要發(fā)生內(nèi)存溢出之前,將把這些對象列進回收范圍之中進行第二次回收,如果這次回收還沒有足夠內(nèi)存則拋出OOM
      • weak reference
        • 當(dāng)gc工作時 無論當(dāng)前內(nèi)存是否夠用 都會回收掉只有弱引用的對象
      • phantom reference
        • 為一個對象設(shè)置一個虛引用唯一目的是在這個對象被收集時受到一個系統(tǒng)通知
    • 生存還是死亡
      • 當(dāng)可達性分析后,判斷一個對象不可達或可達只是存在phantom,weak或soft在回收隊列中時,則第一次標(biāo)記并賽選
        • 賽選條件是:是否有必要執(zhí)行finalize方法
          • 沒有必要:對象沒有覆蓋finalize方法和finalize方法已經(jīng)被JVM調(diào)用過了
      • 有必要執(zhí)行finalize方法的放在f-queue隊列當(dāng)中,jvm自動創(chuàng)建且低優(yōu)先級的Finalizer線程執(zhí)行(這里是觸發(fā)不保證等它運行結(jié)束)
      • finalize方法是對象逃離死亡的最后一次機會
      • 忘掉finalize這個方法的存在
    • 回收方法區(qū)
      • 廢棄常量和無用的類
      • 無用的類(-Xnoclassgc,-verbose:class,-XX:+TraceClassLoading,-XX:+TraceClassUnloading)
        • 該類的所有實例都已經(jīng)回收
        • 加載該類的classloader已經(jīng)被回收
        • 該類對應(yīng)的java.lang.Class對象沒有被引用
  • gc roots

    • gc roots tracing
      • 時間不能耗太多
        • 不需要一個不漏的檢查完所有的執(zhí)行上下文和全局引用位置
        • OopMap的數(shù)據(jù)結(jié)構(gòu)實現(xiàn) 直接從這里得知信息
      • stop the world
    • savepoint
      • 當(dāng)GC需要中斷線程的時候,不直接對線程操作,而是簡單設(shè)置一個標(biāo)志,各個線程執(zhí)行時主動去輪詢這個標(biāo)志,標(biāo)志為真時主動掛起
    • saveregion
      • 對應(yīng)沒有分到cpu的線程既: sleep, blocked等,無法響應(yīng)中斷
      • 安全區(qū)域指:一段代碼片段中 引用關(guān)系不會發(fā)生變化 這個區(qū)域任何地方執(zhí)行GC都是安全的
      • 在線程執(zhí)行到了safe region中的代碼時 標(biāo)識自己進入了safe region 當(dāng)在這段時間里JVM發(fā)起GC 就不用管標(biāo)識自己為safe region狀態(tài)的線程了
        • 在線程要離開safe region時 它要檢查系統(tǒng)是否已經(jīng)完成了根節(jié)點枚舉或整個GC過程 如果完成就繼續(xù)執(zhí)行 否則等待收到可以離開safe region的信號位置
  • savepoint

    • 一直都知道,當(dāng)發(fā)生GC時,正在執(zhí)行Java code的線程必須全部停下來,才可以進行垃圾回收,這就是熟悉的STW(stop the world),但是STW的背后實現(xiàn)原理,比如這些線程如何暫停、又如何恢復(fù)?就比較疑惑了, 然而這一切的一切,都涉及到一個概念safepoint,openjdk的實現(xiàn)位于openjdk/hotspot/src/share/vm/runtime/safepoint.cpp
    • 什么是safepoint
      • safepoint可以用在不同地方,比如GC、Deoptimization,在Hotspot VM中,GC safepoint比較常見,需要一個數(shù)據(jù)結(jié)構(gòu)記錄每個線程的調(diào)用棧、寄存器等一些重要的數(shù)據(jù)
      • 從線程角度看,safepoint可以理解成是在代碼執(zhí)行過程中的一些特殊位置,當(dāng)線程執(zhí)行到這些位置的時候,說明虛擬機當(dāng)前的狀態(tài)是安全的,如果有需要,可以在這個位置暫停,
        • 比如發(fā)生GC時,需要暫停所以活動線程,但是線程在這個時刻,還沒有執(zhí)行到一個安全點,所以該線程應(yīng)該繼續(xù)執(zhí)行,到達下一個安全點的時候暫停,等待GC結(jié)束。
    • 什么地方可以放safepoint
      • 理論上,在解釋器的每條字節(jié)碼的邊界都可以放一個safepoint,不過掛在safepoint的調(diào)試符號信息要占用內(nèi)存空間,如果每條機器碼后面都加safepoint的話,需要保存大量的運行時數(shù)據(jù),所以要盡量少放置safepoint,在safepoint會生成polling代碼詢問VM是否要“進入safepoint”,polling操作也是有開銷的
      • 通過JIT編譯的代碼里,會在所有方法的返回之前,以及所有非counted loop的循環(huán)(無界循環(huán))回跳之前放置一個safepoint,為了防止發(fā)生GC需要STW時,該線程一直不能暫停。另外,JIT編譯器在生成機器碼的同時會為每個safepoint生成一些“調(diào)試符號信息”,為GC生成的符號信息是OopMap,指出棧上和寄存器里哪里有GC管理的指針
  • 線程如何被掛起

    • 如果觸發(fā)GC動作,VM thread會在VMThread::loop()方法中調(diào)用SafepointSynchronize::begin()方法,最終使所有的線程都進入到safepoint
      // Roll all threads forward to a safepoint and suspend them all void SafepointSynchronize::begin() { Thread* myThread = Thread::current(); assert(myThread->is_VM_thread(), "Only VM thread may execute a safepoint"); if (PrintSafepointStatistics || PrintSafepointStatisticsTimeout > 0) { _safepoint_begin_time = os::javaTimeNanos(); _ts_of_current_safepoint = tty->time_stamp().seconds(); } ... }
    • 在safepoint實現(xiàn)中,有這樣一段注釋,Java threads可以有多種不同的狀態(tài),所以掛起的機制也不同,一共列舉了5中情況:
      • 1.執(zhí)行java code
        • 在執(zhí)行字節(jié)碼時會檢查safepoint狀態(tài),因為在begin方法中會調(diào)用Interpreter::notice_safepoints()方法,通知解釋器更新dispatch table
      • 2.執(zhí)行native code
        • 如果VM thread發(fā)現(xiàn)一個Java thread正在執(zhí)行native code,并不會等待該Java thread阻塞,不過當(dāng)該Java thread從native code返回時,必須檢查safepoint狀態(tài),看是否需要進行阻塞
      • 3.執(zhí)行compiled code
        • 如果想進入safepoint,則設(shè)置polling page不可讀,當(dāng)Java thread發(fā)現(xiàn)該內(nèi)存頁不可讀時,最終會被阻塞掛起。在SafepointSynchronize::begin()方法中,通過 os::make_polling_page_unreadable()方法設(shè)置polling page為不可讀
      • 4.線程處于Block狀態(tài)
        • 即使線程已經(jīng)滿足了block condition,也要等到safepoint operation完成,如GC操作,才能返回
      • 5.線程正在轉(zhuǎn)換狀態(tài)
        • 會去檢查safepoint狀態(tài),如果需要阻塞,就把自己掛起
      • 最終實現(xiàn)
        • 當(dāng)線程訪問到被保護的內(nèi)存地址時,會觸發(fā)一個SIGSEGV信號,進而觸發(fā)JVM的signal handler來阻塞這個線程,The GC thread can protect some memory to which all threads in the process can write (using the mprotect system call) so they no longer can. Upon accessing this temporarily forbidden memory, a signal handler kicks in。再看看底層是如何處理這個SIGSEGV信號,實現(xiàn)位于hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp 執(zhí)行os::block_on_serialize_page_trap()把當(dāng)前線程阻塞掛起
    • 線程如何恢復(fù)
      • 有了begin方法,自然有對應(yīng)的end方法,在SafepointSynchronize::end()中,會最終喚醒所有掛起等待的線程,大概實現(xiàn)如下:
      • 1.重新設(shè)置pooling page為可讀
      • 2.設(shè)置解釋器為ignore_safepoints
      • 3.喚醒所有掛起等待的線程
  • 對JVM性能有什么影響

    • 通過設(shè)置JVM參數(shù) -XX:+PrintGCApplicationStoppedTime, 可以打出系統(tǒng)停止的時間
    • 一個大概率的原因是當(dāng)發(fā)生GC時,有線程遲遲進入不到safepoint進行阻塞,導(dǎo)致其他已經(jīng)停止的線程也一直等待,VM Thread也在等待所有的Java線程掛起才能開始GC,這里需要分析業(yè)務(wù)代碼中是否存在有界的大循環(huán)邏輯,可能在JIT優(yōu)化時,這些循環(huán)操作沒有插入safepoint檢查
  • References

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,048評論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,414評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,169評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,722評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,465評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,823評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,813評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,000評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,554評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,295評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,513評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,035評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,722評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,125評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,430評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,237評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,482評論 2 379

推薦閱讀更多精彩內(nèi)容

  • 這篇文章是我之前翻閱了不少的書籍以及從網(wǎng)絡(luò)上收集的一些資料的整理,因此不免有一些不準(zhǔn)確的地方,同時不同JDK版本的...
    高廣超閱讀 15,662評論 3 83
  • http://www.cnblogs.com/angeldevil/p/3801189.html值得一看 Clas...
    snail_knight閱讀 1,443評論 1 0
  • 1.什么是垃圾回收? 垃圾回收(Garbage Collection)是Java虛擬機(JVM)垃圾回收器提供...
    簡欲明心閱讀 89,757評論 17 311
  • Java SE 基礎(chǔ): 封裝、繼承、多態(tài) 封裝: 概念:就是把對象的屬性和操作(或服務(wù))結(jié)合為一個獨立的整體,并盡...
    Jayden_Cao閱讀 2,130評論 0 8
  • 在這個世界上,應(yīng)該有很多人,都躲在云后面,悄悄看看自己喜歡的人吧?
    沒理想的豬閱讀 539評論 0 49