您好,登錄后才能下訂單哦!
這篇文章主要介紹了JVM中的GC知識點有哪些的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇JVM中的GC知識點有哪些文章都會有所收獲,下面我們一起來看看吧。
GC(Garbage Collection)稱之為垃圾回收,是對內存中的垃圾對象,采用一定的算法進行內存回收的一個動作。比方說,java中的垃圾回收會對內存中的對象進行遍歷,對存活的對象進行標記,其未標記對象可認為是垃圾對象,然后基于特定算法進行回收。
深入理解GC的工作機制,可以幫你寫出更好的Java應用,提高開發效率,同時也是進軍大規模應用開發的一個前提。
這個算法是給每一個對象設置一個引用計數器,每當有一個地方引用這個對象的時候,計數器就加 1,與之相反,每當引用失效的時候就減 1。也就是以計數來判斷對象是否為垃圾。當某個對象的引用計數器的值為0時,表示這個對象不會在被實用,JVM中的GC被觸發時,可回收這個對象。如圖所示:
其中:
綠色云朵是內存中的根對象,表示程序中正在使用的對象。
藍色圓圈是內存中的活動對象,其中的數字表示其引用計數。
灰色圓圈是內存中沒有活動對象引用的對象,表示非活動對象。
對于引用計數法,實現簡單,垃圾對應也便于識別。但也有一些缺陷,我們每個對象都需要有一個單獨的對象引用計數器,這個計數器的值還要經常更新,還有就是有一個最嚴重的循環引用問題,如圖所示:
其中紅色對象實際上是應用程序不使用的垃圾。但由于引用計數的限制,仍然存在內存泄漏。當然也有一些辦法來應來對這種情況, 例如 “弱引用”(‘weak’ references)或者使用其它的算法來排查循環引用等。
這個算法的核心思路就是通過一系列的“GC Roots”對象作為起始點,從這些對象開始往下搜索,搜索所經過的路徑稱之為“引用鏈”。當一個對象到 GC Roots 沒有任何引用鏈相連的時候,證明此對象是可以被回收的。否則,證明這個對象有用,不是垃圾。如圖所示:
在GC遍歷(traverses)內存中整體的對象關系圖(object graph)時,首先要確定根對象,那什么樣的對象可作為根對象呢?GC規范中指出根對象可以是:
1)Java 虛擬機棧中的引用對象;
2)本地方法棧中 JNI(既一般說的 Native 方法)引用的對象;
3)方法區中類靜態常量的引用對象;
4)方法區中常量的引用對象。
當確定了根對象以后,進而從根對象開始進行依賴查找,所有可訪問到的對象都認為是存活對象,然后進行標記(mark)。
說明:標記可達對象需要暫停所有應用線程, 以確定對象的引用關系。其暫停的時間, 與堆內存大小、對象的總數沒有直接關系, 而是由存活對象(alive objects)的數量來決定。
標記清除(Mark-Sweep)算法分為“標記”和“清除”階段,它首先會標記出內存中所有不需要回收的對象,然后從內存中清除所有未標記的對象。 如圖所示:
標記清除算法的的優點是簡單直接,缺點是效率低,并且可能會產生大量不連續的碎片。說它效率低是因為標記和清除兩個過程都需要掃描內存空間(第一次:標記存活對象,第二次:清除沒有標記的對象)。還有就是,清除后產生的大量不連續的內存碎片空間,無法滿足較大對象的存儲需求,這樣就可能會再次觸發垃圾回收。所以此垃圾回收算法,應該適合對象存活率較高的的內存區域(比方說JVM中的老年代)。
標記復制(Mark-Copy)算法是將內存分為大小相同的兩塊,當這一塊使用完了,就把當前存活的對象復制到另一塊,然后一次性清空當前區塊。如圖所示:
“標記-復制”算法的缺點顯而易見,就是內存空間利用率低,適用于那些對象生命周期短、回收頻率高的內存區域(比方說JVM中的年輕代)。
標記整理清除(Mark-Sweep-Compact)算法結合了“標記-清除”和“復制”兩個算法的優點。第一階段從根節點開始標記所有被引用對象,第二階段遍歷整個堆,把存活對象“壓縮”復制到堆的其中一塊空間中,按順序排放。第三階段清理掉存活邊界以外的全部內存空間。如圖所示:
系統GC時每次執行清除(sweeping)操作, JVM 都必須保證“不可達對象“占用的內存能被回收然后重用。內存是被回收了,但這有可能會產生大量的內存碎片(類似于磁盤碎片), 進而引發兩個問題:
對象創建時,執行寫入操作越來越耗時, 因為尋找一塊足夠大的空閑內存會變得更加麻煩。
對象創建時, JVM需要在連續的內存塊中為對象分配內存。如果碎片問題很嚴重, 直至沒有空閑片段能存放新創建的對象,就會發生內存分配錯誤(allocation error)。
為了解決碎片問題,JVM在啟動GC執行垃圾收集的過程中, 不僅僅是標記和清除, 還需要執行 “內存碎片整理”。這個過程會讓所有可達對象(reachable objects)進行依次移動,進而可以消除(或減少)內存碎片,并為新對象提供更大并且連續的內存空間。
標記整理算法避免了“標記-清除”的碎片問題,同時也避免了“復制”算法的空間問題,由于需要向一側移動等一系列操作,其效率相對低一些,但對內存空間管理上十分優異。適用于那些生命周期長、回收頻率低,但注重回收一次內存空間得到足夠釋放的場景。
我們知道垃圾收集要停止整個應用程序的運行,那么假如這個收集過程需要的時間很長,就會對應用程序產生很大性能問題,如何解決這個問題呢?通過實驗發現內存中的對象通常可以將其分為兩大類:
存活時間較短(這樣的對象比較多)。
存活時間較長(這樣的對象比較少)。
基于對如上問題的分析,科學家提出了分代回收思路,將VM中內存分為年輕代(Young Generation)和老年代(Old Generation-老年代有時候也稱為年老區(Tenured)。例如:
Young區存儲的就是那些生命周期短,使用一兩次就不再使用的對象,回收一次基本上該區域十之有八的對象全部被回收清理掉,因此Young區采用的垃圾回收算法也就是“標記-復制”算法。Old區存儲的是那些生命周期長,經過多次回收后仍然存活的對象,就把它們放到Old區中,Old區一般不去判斷這些對象的可達性,直到Old區不夠用為止,再進行一次統一的回收,釋放出足夠的連續的內存空間。所以我們選擇“標記-清除”或“標記-整理”算法進行垃圾收集。
在分代回收過程中,垃圾收集事件(Garbage Collection events)通常分為:
Minor GC (小型GC):年輕代GC事件,(新對象)分配頻率越高, Minor GC 的頻率就越高。
Major GC (大型GC): 老年代GC事件。
Full GC (完全GC):整個堆的GC事件。
說明:一般情況下可以將Major GC與Full GC看成是同一種GC。
關于“JVM中的GC知識點有哪些”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“JVM中的GC知識點有哪些”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。