1. 程式人生 > >java 物件存活分析——引用計數法&可達性分析

java 物件存活分析——引用計數法&可達性分析

java虛擬機器總共分為五個區域,其中三個是執行緒私有:程式計數器,虛擬機器棧,本地方法棧,兩個是執行緒共享:堆,方法區。執行緒私有的區域等到執行緒結束時(棧幀出棧時)會自動被釋放,空間比較容易清理。而執行緒共享的java堆和方法區中的空間較大而且沒有執行緒的回收容易產生很多垃圾資訊,GC垃圾回收真正關心的就是這部分。

java堆和方法區主要存放各種型別的物件(方法區中也儲存一些靜態變數和全域性常量等資訊),那麼我們在使用GC對其進行回收的時候首先要考慮的就是如何判斷一個物件是否應該被回收。也就是要判斷一個物件是否還有其他的引用或關聯使得這個物件處於存活的狀態。我們需要將不在存活狀態的所有物件標記出,以便於GC進行回收。

判斷物件是否存活有兩種比較常見的方法:引用計數法可達性分析演算法

引用計數法

引用計數法的邏輯非常簡單,但是存在問題,java並不採用這種方式進行物件存活判斷。

引用計數法的邏輯是:在堆中儲存物件時,在物件頭處維護一個counter計數器,如果一個物件增加了一個引用與之相連,則將counter++。如果一個引用關係失效則counter–。如果一個物件的counter變為0,則說明該物件已經被廢棄,不處於存活狀態。

這種方法來標記物件的狀態會存在很多問題:

1 jdk從1.2開始增加了多種引用方式:軟引用、弱引用、虛引用,且在不同引用情況下程式應進行不同的操作。如果我們只採用一個引用計數法來計數無法準確的區分這麼多種引用的情況。

引用計數法無法解決多種型別引用的問題。但這並不是致命的,因為我們可以通過增加邏輯區分四種引用情況,雖然麻煩一些但還算是引用計數法的變體,真正讓引用計數法徹底報廢的下面的情況。

2 如果一個物件A持有物件B,而物件B也持有一個物件A,那發生了類似作業系統中死鎖的迴圈持有,這種情況下A與B的counter恆大於1,會使得GC永遠無法回收這兩個物件。

可達性分析演算法

在主流的商用程式語言中(Java和C#),都是使用可達性分析演算法判斷物件是否存活的。這個演算法的基本思路就是通過一系列名為GC Roots的物件作為起始點,從這些節點開始向下搜尋,搜尋所走過的路徑稱為引用鏈(Reference Chain),當一個物件到GC Roots沒有任何引用鏈相連時,則證明此物件是不可用的,下圖物件object5, object6, object7雖然有互相判斷,但它們到GC Roots是不可達的,所以它們將會判定為是可回收物件。

這裡寫圖片描述

那麼那些點可以作為GC Roots呢?一般來說,如下情況的物件可以作為GC Roots:

  1. 虛擬機器棧(棧楨中的本地變量表)中的引用的物件
  2. 方法區中的類靜態屬性引用的物件
  3. 方法區中的常量引用的物件
  4. 本地方法棧中JNI(Native方法)的引用的物件

HotSpot虛擬機器如何實現可達性演算法?

java中的主流虛擬機器HotSpot採用可達性分析演算法來確定一個物件的狀態,那麼HotSpot在具體實現該演算法時採用了哪些結構?

使用OopMap記錄並列舉根節點

HotSpot首先需要列舉所有的GC Roots根節點,虛擬機器棧的空間不大,遍歷一次的時間或許可以接受,但是方法區的空間很可能就有數百兆,遍歷一次需要很久。更加關鍵的是,當我們遍歷所有GC Roots根節點時,我們需要暫停所有使用者執行緒,因為我們需要一個此時此刻的”虛擬機器快照”,如果我們不暫停使用者執行緒,那麼虛擬機器仍處於執行狀態,我們無法確保能夠正確遍歷所有的根節點。所以此時的時間開銷過大更是我們不能接受的。

基於這種情況,HotSpot實現了一種叫做OopMap的資料結構,這種資料結構在類載入完成時把物件內的偏移量是什麼型別計算出,並且存放下位置,當需要遍歷根結點時訪問所有OopMap即可。

用安全點Safepoint約束根節點

如果將每個符合GC Roots條件的物件都存放進入OopMap中,那麼OopMap也會變得很大,而且其中很多物件很可能會發生一些變化,這些變化使得維護這個對映表很困難。實際上,HotSpot並沒有為每一個物件都建立OopMap,只在特定的位置上建立了這些資訊,這些位置稱為安全點(Safepoints)。

為了保證虛擬機器中安全點的個數不算太多也不是太少,主要決定安全點是否被建立的因素是時間。當進行了耗時的操作時,比如方法呼叫、迴圈跳轉等時會產生安全點。此外,HotSpot虛擬機器在安全點的基礎上還增加了安全區域的概念,安全區域是安全點的擴充套件。在一段安全區域中能夠實現安全點不能達成的效果。

相關推薦

java 物件存活分析——引用計數&分析

java虛擬機器總共分為五個區域,其中三個是執行緒私有:程式計數器,虛擬機器棧,本地方法棧,兩個是執行緒共享:堆,方法區。執行緒私有的區域等到執行緒結束時(棧幀出棧時)會自動被釋放,空間比較容易清理。而執行緒共享的java堆和方法區中的空間較大而且沒有執行緒的回

Java虛擬機器判斷物件存活的兩種方案:引用計數分析演算法

java堆和方法區主要存放各種型別的物件(方法區中也儲存一些靜態變數和全域性常量等資訊),那麼我們在使用GC對其進行回收的時候首先要考慮的就是如何判斷一個物件是否應該被回收。也就是要判斷一個物件是否還有其他的引用或關聯使得這個物件處於存活的狀態。我們需要將不在存活狀態的所有物

JVM----判斷物件是否存活 : 引用計數演算法OR分析演算法?

本篇來自周志明的<<深入理解java虛擬機器>> 在堆裡面存放著Java世界中幾乎所有的物件例項,垃圾收集器在對堆進行回收前,第一件事情就是要確定這些物件之中哪些還“存活”著 ,哪些已經“死去”(即不可能再被任何途徑使用的物件)。 引用計數演算法 很多教科書判斷物

垃圾回收——判斷物件是否存活演算法-引用計數詳解

垃圾回收首要的任務就是確定哪些物件是垃圾,哪些物件可進行回收,上節課我們也說過了,判定物件為垃圾物件的兩種演算法,一種是引用計數法,另一種是可達性分析法,我們本節課就來詳細的瞭解一下什麼是引用計數法。 引用計數法的思路是,在物件中新增一個引用計數器,當有地方引用這個物件的時候,這個引用計數器的值

深入理解JVM——引用計數分析演算法(理解)

引言JVM中的堆和方法區主要用來存放物件(方法區中也儲存了一些靜態變數和全域性變數等資訊),那麼我們要使用GC演算法對其進行回收時首先要考慮的就是該物件是否應該被回收。即判斷該物件是否還有其他的引用或者

JVM中垃圾回收機制如何判斷是否死亡?詳解引用計數分析

> 因為熱愛,所以堅持。 > 文章下方有本文參考電子書和視訊的**下載地址**哦~ 這節我們主要講垃圾收集的一些基本概念,先了解垃圾收集是什麼、然後觸發條件是什麼、最後虛擬機器如何判斷物件是否死亡。 ### 一、前言   我們都知道Java和C++有一個非常大的區別就是Java有自動的垃圾回收

JVM 中判斷物件是否 “存活” 的演算法 —— 分析演算法

在堆中,幾乎存放著所有的物件例項,那麼回收這些物件例項時,我們需要判斷哪些物件是 “已死” 可以回收的,哪些物件是 “存活” 不需要回收的,下面就來介紹一下 JVM 中如何判斷上述問題的。 基本思路 通過一系列的稱為“GC Roots”的物件作為起始點,從這些節點開

JVM——引用計數演算法與分析演算法

前幾篇部落格我們一起認識了JVM的記憶體模型(程式計數器、虛擬機器棧、本地方法棧、方法區與堆),瞭解了它們的記憶體結構與分配,同時也略帶提到關於記憶體的回收。 JVM——記憶體模型(一):程式計數器 JVM——記憶體模型(二):虛擬機器棧與本地方法棧 JVM——記憶體模型(三):堆與方法

java垃圾回收之 引用計數

基本概念在物件中引入計數器(無符號整數),用於記錄有多少物件引用了該物件。通過增減計數器實現對記憶體的管理。分配物件時將計數器置1。更新引用時先對新指定的物件進行計數器加,而後才對舊物件進行減。在對計數

判斷物件存活分析演算法

判斷物件存活,常用的方式是引用計數器:每當物件被一個地方引用,計數器便+1;當引用失效時,計數器-1。當物件的計數器為0時,該物件便是一個不被使用的物件,即“死亡”。引用計數器實現簡單,效率高。然而難以解決物件之間相互迴圈引用的問題(兩個失效物件相互儲存了對方的指標)。故JV

分析-確定那些對象是垃圾(轉)

article ima -1 ability rdquo 靜態 roots 關聯 csdn 在主流的商用程序語言(Java、C#,甚至包括前面提到的古老的Lisp)的主流實現中,都是稱通過可達性分析(Reachability Analysis)來判定對象是否存活的。這個算法

Java記憶體回收之分析演算法

Java記憶體回收時的可達性分析演算法 也稱為傳遞跟蹤演算法; Java中,是通過可達性分析演算法來判斷物件是否存活的。 1:演算法的思路 通過一系列的“GC Roots”物件作為起點,開始向下搜尋 搜尋所走過的路徑稱為引用鏈; 當一個物件到GC Roots沒有

JVM分析演算法-判斷回收的物件

一JVM判斷哪些物件需要回收判斷物件是否需要回收,主要依據是該物件是否被其它地方引用。而判斷該物件是否被其它地方引用,主要有兩種演算法來實現。1、引用計數演算法該演算法的實現原理是:給物件一個引用計數器,每當有一個地方引用它時,計數器值就加1,當引用計數器失效時,計數器的值就

GC分析回收演算法 解決迴圈引用問題 強引用引用

JVM有一個回收演算法是引用計數演算法,每當物件被引用一次,就+1,釋放一個引用就-1,當垃圾回收時,引用計數為0的物件就會被GC掉。但這個方法有個問題,就是無法解決迴圈引用的問題。 迴圈引用就是物件A引用了物件B,物件B引用了物件A,構成了一個引用環。彼此都沒發揮什麼作用

jvm原理四:利用分析演算法GC怎麼判斷物件生存還是死亡,經過了幾次過濾,每次都做了什麼

經歷了2次標記過程,即2次過濾過程。第一次:如果物件在進行可達性分析後發現沒有GC Roots相連線的引用鏈,那它將會被第一次標記並且進行一次篩選,篩選的條件是此物件是否有必要執行finalize()方

JAVA垃圾回收-分析演算法

在java中是通過引用來和物件進行關聯的,也就是說如果要操作物件,必須通過引用來進行。那麼很顯然一個簡單的辦法就是通過引用計數來判斷一個物件是否可以被回收。不失一般性,如果一個物件沒有任何引用與之關聯,則說明該物件基本不太可能在其他地方被使用到,那麼這個物件就成為可被回收的物

GC 分析演算法

在主流的商用程式語言的主要實現中,都是稱通過可達性分析(Reachability Analysis)來判定物件是否存活的,這個演算法的基本思路就是通過一系列的稱為“GC Roots“的物件作為起始點,從這些節點開始向下搜尋,搜尋所走過的路程成為引用鏈(Reference Chain),當一個物件

分析演算法

在Java語言中,可作為GC Roots的物件包括下面幾種:   a) 虛擬

簡單分析

C Roots的物件作為起始點,從這些節點開始向下搜尋,搜尋所走過的路徑稱為引用鏈,當一個物件到GC Roots沒有任何引用鏈相連

面試官:你說你熟悉jvm?那你講一下併發的分析

這是why技術的第35篇原創文章 上面這張圖是我還是北漂的時候,在鼓樓附近的衚衕裡面拍的。 那天剛剛下完雨,路過這個地方的時候,一瞬間就被這五顏六色的門板和自行車給吸引了,於是拍下了這張圖片。看到這張圖片的時候我就很開心,多鮮活、多舒服的畫面呀。 以後的文章裡面我的第一張配圖都用自己隨時拍下的照片吧。分享