根節(jié)點枚舉
在可達性算法當中是通過GC ROOT的引用找到存活對象的方式臀玄,在現(xiàn)代的收集器基本可以做到和用戶線程一起并發(fā)執(zhí)行的程度钧舌,但是根節(jié)點枚舉要保證某個時間點的“快照”董饰,這也意味著根節(jié)點枚舉需要暫停用戶線程旁壮。
一套完整的“GC Roots”也必須考慮分代回收和局部回收的問題偶宫。例如 Partial GC 針對堆中某塊區(qū)域的發(fā)起垃圾回收時哥牍,也必須考慮此內(nèi)存區(qū)域內(nèi)的對象是否可能被其他區(qū)域引用露懒? 所以此時也必須將這些關(guān)聯(lián)區(qū)域的對象一起加入到“GC Roots”集合里闯冷,才能保證可達性分析的正確性。
OopMap 數(shù)據(jù)結(jié)構(gòu)
枚舉出整個“GC Roots”是非常麻煩的
- 運行時數(shù)據(jù)本身就是動態(tài)的懈词。
- Java應(yīng)用越來越大蛇耀。
JVM 如何解決呢?
首先在進行根節(jié)點選舉時坎弯,必須暫停全部的用戶線程纺涤,我們把這個過程稱為“Stop The Word”(下面簡稱STW)(注:但必須要說明,STW不一定是全局的抠忘,也可以是局部的撩炊,這和安全點的類型有關(guān)。此時說的必須暫停全部用戶線程只是因為GC時必須使全部線程進入安全點(gc safe point))崎脉。
在HotSpot的解決方案中拧咳,是使用一組稱為OopMap的數(shù)據(jù)結(jié)構(gòu)來存放這些對象的引用(OopMap在類加載動作完成時生成)。也就是說當用戶線程暫停下來之后囚灼,其實并不需要一個不漏的檢查完所有的執(zhí)行上下文和全局的引用位置骆膝。而是直接通過OopMap來獲取棧上或寄存器里哪里有GC管理的指針(引用指針)。
這種結(jié)構(gòu)會存在哪些問題灶体?
這里可以看到阅签,如果每一次對象的讀取變化,都需要往OopMap里面存儲內(nèi)容蝎抽,會導致OopMap的內(nèi)容不斷臃腫擴大政钟,垃圾收集器的掃描成本會變得非常的昂貴。
為了應(yīng)對這一類問題樟结,HotSpot引入了“安全點這一機制進行處理”养交。