HotSpot 虛擬機垃圾回收算法實現

作為使用范圍最廣的虛擬機之一HotSpot,必須對垃圾回收算法的執行效率有嚴格的考量,只有這樣才能保證虛擬機高效運行

枚舉根節點

從可達性分析中從 GC Roots 節點找引用鏈這個操作為例,可以作為 GC Roots 的節點主要在全局性的引用(例如常量或者類靜態屬性)與執行上下文(例如棧幀中的本地變量表)中。

但是現在很多應用僅僅方法區就有數百兆,如果要逐個檢查這里面的引用,那么必然會消耗很多的時間。

另外,可達性分析對執行時間的敏感還體現在 GC 停頓上,因為這項分析工作必須在一個能確保一致性的快照中進行 —— 這里的“一致性”指的是在整個分析過程中整個執行系統看起來就像是被凍結在某個時間點上,不可以出現分析過程中對象引用關系還在不停變化的情況,該點不滿足的話分析結果準確性就無法得到保證。

這點是導致 GC 進行時必須停頓所有 Java 執行線程的其中一個重要原因,即使是號稱不會發生停頓的 CMS 收集器中,枚舉根節點也是必須要停頓的。

由于目前主流 Java 虛擬機使用的都是準確式 GC,所以當執行系統停頓下來后,并不需要一個不漏的檢查完成所有執行上下文和全局的引用位置,虛擬機應當是有辦法直接得知那些地方存放著對象引用的。 在HotSpot的實現中,是使用一組被稱為OopMap的數據結構來達到這個目的的,在類加載的時候,HotSpot就把對象內什么偏移量上是什么類型的數據計算出來,在JIT 編譯過程中,也會在特定的位置記錄下棧和寄存器中哪些位置是引用。這樣, GC 在掃描時就可以直接得知這些信息了。

安全點

在 OopMap 的幫助下,HotSpot 可以快速并且準確的完成 GC Roots 枚舉,但是一個很現實的問題隨之而來:可能導致引用關系變化,或者說 OopMap 內容變化的指令非常多,如果為每一條指令都生成對應的 OopMap,那么將需要大量的額外空間,這樣 GC 的空間成本將會變得很高。

實際上,HotSpot 也的確沒有為每一條指令都生成 OopMap,只是在“特定的位置” 記錄了這些信息,這些位置被稱為是安全點,即程序執行時并非是在所有地方都能停頓下來開始 GC ,只有到達安全點時才能暫停。

安全點的選擇既不能太少以至于讓 GC 等待太長時間,也不能過于頻繁以至于過分增大運行時負荷。

所以,安全點的選定基本上是以程序“是否具有讓程序長時間執行的特征”為標準進行選定的——因為每條指令執行的時間都非常短暫,程序不太可能因為指令流長度太長這個原因而過長時間運行,“長時間執行”的最明顯特征就是指令序列復用,例如方法調用、循環跳轉、異常跳轉等,所以具有這些功能的指令才會產生安全點。

對于安全點,另一個需要考慮的問題就是如何讓 GC 發生時讓所有線程(這里不包括執行 JNI 調用的線程)都“跑”到最近的安全點再停頓下來。這里有兩種方案可供選擇:搶先式中斷和主動式中斷。

  • 搶先式中斷:無需線程的執行代碼主動配合,在 GC 發生時,首先把所有線程全部中斷,如果發現有線程中斷的地方不再安全點上,就會發線程,讓它“跑”到安全點上。現在幾乎沒有虛擬機實現采用搶先式中斷來暫停線程從而響應GC事件
  • 主動式中斷:當 GC 需要中斷線程時,不直接對線程操作,僅僅簡單地設置一個標志,各個線程執行時主動去輪詢這個標志,發現中斷標志為真時就自己中斷掛起。輪詢標志的地方和安全點是重合的,另外再加上創建對象需要分配內存的地方。

安全區域

使用安全點似乎已經完美解決了如何進入 GC 的問題,但實際情況卻并不一定,安全點機制保證了程序執行,在不太長的時間內就會遇到可以進入 GC 的安全點。

但是線程“不執行”的時候呢?所謂不執行就是沒有分配 CPU 時間,典型的例子就是線程處于 Sleep 狀態或者 Blocked狀態,這時候線程無法響應 JVM 的中斷請求,“走”到安全點去中斷掛起,JVM顯然也不太可能等待線程重新被分配 CPU 時間。對于這種狀況,就需要安全區域來解決。

安全區域就是在一段代碼片段中,引用關系不會發生變化,在這個區域中的任意地方開始 GC 都是安全的。

在線程執行到安全區域中的代碼時,首先標識自己已經進入了安全區域,那樣,當這段時間里 JVM 要發起 GC 時,就不用管標識自己為安全區域狀態的線程了。

當線程要離開安全區域時,它要檢查系統是否已經完成了根節點枚舉(或者是整個 GC 過程),如果完成了,那線程就繼續執行,否則它就必須等待直到收到可以安全離開安全區域的信號為止。

轉載于:https://www.cnblogs.com/AmosH/p/10346924.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/387474.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/387474.shtml
英文地址,請注明出處:http://en.pswp.cn/news/387474.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java NIO編寫Socket服務器的一個例子

最近一直在忙著JAVA NIO的知識,花了一下午的時間,總算寫出了一個可以運行的程序,廢話少說,上代碼! Java代碼: import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerS…

2.5 map

#include<map> key/value對 采用紅黑樹實現&#xff0c;鍵值不允許重復 用法與set類似 創建map&#xff1a; map<string, float> m; m["haha"] 11.1; m["hehe"] 22.2; for (map<string, float>::iterator it m.begin(); it ! m.en…

在js傳遞參數中含加號(+)的處理方式

一般情況下&#xff0c;url中的參數應使用 url 編碼規則&#xff0c;即把參數字符串中除了 “ - "、" _ " 、" . "之外的所有非字母數字字符都將被替換成百分號&#xff08;%&#xff09;后跟兩位十六進制數&#xff0c;空格則編碼為加號&#xff08;…

二 SVN代碼沖突的解決

問題&#xff1a; A和B都是最新的代碼&#xff0c;A修改了代碼提交了&#xff0c;B也修改了代碼&#xff0c;但是B提交的時候出現沖突的問題。 解決方案&#xff1a;編輯沖突 解決沖突&#xff1a; 方法一&#xff1a;將文件里面沖突的描述去掉&#xff0c;重新提交 方法二&…

Android7.0反射類找不到的問題

Java中使用反射的地方較多&#xff0c;尤其是各種框架中。最近在Android7.0的項目中遇到個問題很奇怪&#xff0c;反射使用的類找不到了&#xff0c;但是編譯的時候沒問題啊。然后在代碼中使用非反射的方式調用代碼也是沒有問題的&#xff0c;這時奇怪的現象出現了&#xff0c;…

2.6 multimap

#include<map> multimap的元素插入、刪除、查找與map不同 multimap元素的插入&#xff1a;&#xff08;未提供mm[key]value插入方式&#xff09; multimap<string, double> mm; mm.insert(pair<string, double>("haha", 11.1)); mm.insert(pai…

Mybatis學習筆記18 - 緩存

兩級緩存&#xff1a; 一級緩存&#xff1a;&#xff08;本地緩存&#xff09;&#xff1a;sqlSession級別的緩存。一級緩存是一直開啟的&#xff1b;SqlSession級別的一個Map 數據庫同一次會話期間查詢到的數據會放在本地緩存中。以后如果需要獲取相同的數據&#xff0c;直接從…

2.7 deque

#include<deque> 雙端隊列容器 注意&#xff1a;頭入隊時伴隨的是尾出隊&#xff1b;提供中間元素的更新和刪除操作。 與vector一樣&#xff0c;采用線性表順序存儲結構 deque采用分塊的線性存儲結構來存儲數據&#xff0c;每塊大小一般為512字節 所有deque塊由一個…

APK 加殼方法

下載工具http://download.csdn.net/download/sys025/8958363一款免費的為apk加固的工具。 特別說明&#xff1a;加固后需要重新簽名apk才能安裝。加固的apk包會比未加固的大一些。 jarsigner -verbose -keystore dms.keystore -storepass pactera -keypass pactera -sigfile CE…

Java DSL簡介(收集整理)

一、領域特定語言&#xff08;DSL&#xff09; 領域特定語言&#xff08;DSL&#xff09;通常被定義為一種特別針對某類特殊問題的計算機語言&#xff0c;它不打算解決其領域外的問題。對于DSL的正式研究已經持續很多年&#xff0c;直 到最近&#xff0c;在程序員試圖采用最易讀…

[轉]JSon數據解析的四種方式

轉至http://blog.csdn.net/enuola/article/details/7903632 作為一種輕量級的數據交換格式&#xff0c;json正在逐步取代xml&#xff0c;成為網絡數據的通用格式。 有的json代碼格式比較混亂&#xff0c;可以使用此“http://www.bejson.com/”網站來進行JSON格式化校驗&#xf…

2.8 list

#include<list> 雙向循環鏈表 list結點的三個域&#xff1a;數據域、前驅元素指針域、后繼元素指針域 對于list的迭代器&#xff0c;只有或--的操作&#xff0c;無n或-n的操作 創建list對象&#xff1a; list<int> l; list<int> l(10); 插入和遍歷&…

Spring AOP兩種實現機制是什么?

Spring AOP兩種實現機制是什么&#xff1f; 1.如果是有接口聲明的類進行AOP 時&#xff0c;spring調用的是java.lang.reflection.Proxy 類來做處理 2.如果是沒有接口聲明的類時&#xff0c; spring通過cglib包和內部類來實現 在AOP&#xff0c;權限控制&#xff0c;事務管理等…

iOS開發UI篇—Quartz2D使用(繪圖路徑)

1 //1.獲取圖形上下文 2 CGContextRef ctxUIGraphicsGetCurrentContext(); 3 //2.繪圖&#xff08;畫線&#xff09; 4 //設置起點 5 CGContextMoveToPoint(ctx, 20, 20); 6 //設置終點 7 CGContextAddLineToPoint(ctx, 200, 300); 8 //渲染 9…

2.9 bitset

#include<bitset> bitset容器是一個bit位元素的序列容器&#xff0c;每個元素只占一個bit位&#xff0c;取值為0或1&#xff0c;因而很節省內存空間。 bitset<n> b; b.any() 是否有1 b.none() 是否無1 b.count() 1的個數 b.size() 大小 b[pos] 訪問 b.…

C# 談談Interface和通過Interface傳遞web頁面數據

接口&#xff1a;描述可屬于任何類或結構的一組相關功能&#xff0c;通過interface關鍵字來聲明&#xff1b;接口只包含方法、委托或事件和屬性的簽名&#xff08;接口包含的成員&#xff09;、不能包含字段&#xff08;因為字段是包含數據的&#xff09;。方法的實現是“繼承”…

Spring支持如下5種作用域

當通過Spring容器創建一個Bean實例時&#xff0c;不僅可以完成Bean實例的實例化&#xff0c;還可以為Bean指定特定的作用域。Spring支持如下5種作用域&#xff1a; singleton&#xff1a;單例模式&#xff0c;在整個Spring IoC容器中&#xff0c;使用singleton定義的Bean將只有…

RBAC授權

給用戶授予RBAC權限沒有權限會報如下錯誤&#xff1a;執行查看資源報錯&#xff1a; unable to upgrade connection: Forbidden (userkubernetes, verbcreate, resourcenodes, subresourceproxy)[roottest4 ~]# kubectl exec -it http-test-dm2-6dbd76c7dd-cv9qf sh error: una…

出卷子

http://chujuanzi.com/ 出卷子 涵蓋初高中全部學科題庫&#xff0c;全國名校試卷最快更新。試卷新、試題全、解析準、完全免費&#xff0c;提供豐富試題輔助教師有效出試卷&#xff0c;組卷方便快捷。&#xff08;高中語文 高中數學 高中英語 高中物理 高中化學 高中生物 高中政…

2.10 stack

#include<stack> 后進先出 Last In First Out LIFO 插入和刪除元素只能在表的一端進行。 插入端 棧頂 Stack Top 入棧 Push 刪除端 棧底 Stack Bottom 出棧 Pop stack<int> s; s.push(1); //入棧 int i s.top(); //獲得棧頂元素 s.pop(); //出棧 s.size…