JVM: 對象的創建,類加載機制,垃圾回收機制,如何判斷對象已死,垃圾回收的方法

對象的創建:

 

當虛擬機遇到一條new指令時,首先去常量池檢查是否有這條指令所對應的符號引用,並且要檢查這個符號引用所代表的類是否已經類加載了。如果沒有,就必須先執行類加載的過程。然後就要爲這個對象分配內存,相當於我們在java堆劃分一塊大小合適的內存給這個對象。但是劃分內存的方式,要看java內存是否是規整,如果是,java堆就相當於,用過的內存在一邊,沒用的在另一邊,然後是一個指針進行分割,給新對象分配時,就把指針向沒有用過的那邊偏移一點,偏移的距離是跟據對象所佔內存大小來決定,這種方式是“指針碰撞”。如果不規整,java堆的空閒區域和已用是交叉的,那麼需要一個列表去記錄哪一塊是已有哪一塊空閒。然後再去選一塊足夠大的區域分配給這個對象實例,這種叫“空閒列表”。同時,還需要考慮對象創建時是很頻繁的,在併發的情況下,線程並不安全。我可以對分配對象內存空間這種行爲進行一個同步處理,還有就是每個線程可以在java堆細分一塊屬於自己的分配緩衝區,哪個線程要分配內存就在自己的分配緩存區去分配。內存分配完成後,需要將內存分配到的空間都初始化爲零值,這樣保證了我們在java代碼中不用賦初值,就可以直接使用。然後虛擬機對對象進行一些必要的設置,如這個對象屬於哪個類,如何找到這個對象的數據信息等信息,把這些信息存放在對象頭。這樣一個對象就算是創建出來了。

 

 

 

 

 

 

類加載機制:

虛擬機把class文件加載到內存中,進行安全校驗,數據類型解析,初始化和內存分配。最終形成可以被虛擬機直接使用的java類型。

 

類加載 :加載--->驗證---->準備---->解析---->初始化

1、加載:  加載階段需要完成三件事:

    1)獲取此類的二進制字節流

    2)將這個字節流所代表的靜態儲存結構轉換成方法去運行時的數據結構

    3)在這個方法區中去生一個java.lang.class對象,作爲方法區數據的訪問入口

2、驗證: 驗證是時間最長的一個階段,從加載階段開始,持續到解析階段,是進行一個class文件的二進制字節碼的驗證,看它是否滿足虛擬機規範的二進制字節目,因爲如果出現不安全的二進制字節碼,可能會使虛擬機崩潰

  驗證階段又可以分爲:文件格式驗證、元數據驗證、字節碼驗證、符號引用驗證

  1.文件格式驗證:驗證字節流文件是否符合Class文件格式的規範,並且能被當前虛擬機正確的處理。

 

  2.元數據驗證:是對字節碼描述的信息進行語義分析,以保證其描述的信息符合Java語言的規範。

 

  3.字節碼驗證:主要是進行數據流和控制流的分析,保證被校驗類的方法在運行時不會危害虛擬機。

 

  4.符號引用驗證:符號引用驗證發生在虛擬機將符號引用轉化爲直接引用的時候,這個轉化動作將在解析階段中發生。

 

3、準備:準備階段是正式對對類變量進行分配和設置初始化值的一個階段,這些變量都在方法區。,而不包括類的實例變量。對已非final的變量,JVM會將其設置成“零值”,而不是其賦值語句的值:

4、解析:解析階段就是虛擬機將符號引用轉化爲直接引用的過程。主要包括四種類型:類或接口解析,字段解析,方法解析,接口方法解析

5、初始化:在準備階段,類變量已經初始化過一次了,在這個階段,則是根據程序員通過程序制定的計劃區初始化類的變量和其它資源。

 

 

 

垃圾回收機制:

1、在jvm中,程序計數器,java棧,本地方法棧是不用進行垃圾回收的,因爲他們的生命週期隨線程同步,他們佔用的內存會自動釋放,只有方法區和java堆需要GC。

GC的主要任務是:

1、分配內存

2、確保被引用對象的內存不會被錯誤回收

3、回收不在被引用的對象的內存空間

垃圾回收主要解決的三個問題是:

1、那些內存需要回收

2、什麼時候回收

3、如何回收

 

如何判斷哪些內存應該被回收?(如何判斷對象已死?)

判斷方法:

1、引用計數算法:就是當一個地方引用它,計數器就+1,失效時,就-1,計數器=0,就代表它沒有引用指向了。但是如果兩個對象互相引用,就不會被回收了,因此引用算法也不可靠。

2、可達性算法:就是把一系列“GC roots" 作爲起始點,然後向下搜索,路徑稱爲引用鏈,當一個對象的GC root沒有任何引用鏈相連,代表對象不可用。

 

什麼時候被回收?

即使是不可達對象,也要進行二次篩選,如果對象沒有覆蓋finalize方法,或者finalize方法已經被虛擬機調用過了,就沒有必要去執行。

如果有必要就在finalizer線程執行。

 

如何回收?垃圾收集算法

1、清除-標記法:

    第一次掃描對存活的對象進行標記,然後再進行第二次掃描,掃描整個空間中沒有被標記的對象,然後回收。

   缺點:1、每個對象都有掃描,而且要掃描兩遍,效率低,收集的時間也長

             2、產生不連續的內存碎片

 2、複製算法:

    把內存分爲兩塊大小相等的區域,每次只使用其中一塊,當這一快用完了, 就把存活的對象全複製到另外的一塊內存區域中去,然後再清除前一塊空間,這樣就不會出現內存碎片問題。

   缺點:1、複製代價高  2、需要兩個空間,總有一個空間是空閒的,浪費空間

3、標記-整理法:

   依然是把內存掃描一遍,標記出存活的對象,然後把存活的對象移動到內存的一邊,然後清除邊界以外的內存。

    這種方法也不會造成內存碎片,但是會有移動的成本

4、分代收集算法:

    這是不部分jvm的垃圾收集器採用的算法,它將對象存活的生命週期作爲分類依據,分爲新手代,老年代,永久代,老年代特點是每次收集時,只要少部分會被收集走,新生代就是大部分都會被回收,那麼我們就可以根據不同代的特點去選擇他們各自合適的收集算法。

 

JVM查看gc命令:

jstat -gc 12538 5000

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章