垃圾收集器與Java程式設計
垃圾收集器與Java程式設計[@more@] 垃圾收集器(Garbage Collector,GC)對Java程式設計師來說,基本上是透明的,但是一個優秀的Java程式設計師必須瞭解GC的工作原理、如何最佳化GC的效能、如何與GC進行有限的互動,因為有一些應用程式對效能要求較高,例如嵌入式系統、實時系統等,只有全面提升記憶體的管理效率 ,才能提高整個應用程式的效能。本篇文章首先簡單介紹GC的工作原理之後,然後再對GC的幾個關鍵問題進行深入探討,最後提出一些Java程式設計建議,從GC角度提高Java程式的效能。
GC的基本原理
Java的記憶體管理實際上就是物件的管理,其中包括物件的分配和釋放。
對於程式設計師來說,分配物件使用new關鍵字;釋放物件時,只要將物件所有引用賦值為null,讓程式不能夠再訪問到這個物件,我們稱該物件為"不可達的"。GC將負責回收所有"不可達"物件的記憶體空間。
對於GC來說,當程式設計師建立物件時,GC就開始監控這個物件的地址、大小以及使用情況。通常,GC採用有向圖的方式記錄和管理堆(heap)中的所有物件(詳見 參考資料1 )。透過這種方式確定哪些物件是"可達的",哪些物件是"不可達的"。當GC確定一些物件為"不可達"時,GC就有責任回收這些記憶體空間。但是,為了保證GC能夠在不同平臺實現的問題,Java規範對GC的很多行為都沒有進行嚴格的規定。例如,對於採用什麼型別的回收演算法、什麼時候進行回收等重要問題都沒有明確的規定。因此,不同的JVM的實現者往往有不同的實現演算法。這也給Java程式設計師的開發帶來行多不確定性。本文研究了幾個與GC工作相關的問題,努力減少這種不確定性給Java程式帶來的負面影響。
增量式GC( Incremental GC )
GC在JVM中通常是由一個或一組程式來實現的,它本身也和使用者程式一樣佔用heap空間,執行時也佔用CPU。當GC程式執行時,應用程式停止執行。因此,當GC執行時間較長時,使用者能夠感到Java程式的停頓,另外一方面,如果GC執行時間太短,則可能物件回收率太低,這意味著還有很多應該回收的物件沒有被回收,仍然佔用大量記憶體。因此,在設計GC的時候,就必須在停頓時間和回收率之間進行權衡。一個好的GC實現允許使用者定義自己所需要的設定,例如有些記憶體有限有裝置,對記憶體的使用量非常敏感,希望GC能夠準確的回收記憶體,它並不在意程式速度的放慢。另外一些實時網路遊戲,就不能夠允許程式有長時間的中斷。增量式GC就是透過一定的回收演算法,把一個長時間的中斷,劃分為很多個小的中斷,透過這種方式減少GC對使用者程式的影響。雖然,增量式GC在整體效能上可能不如普通GC的效率高,但是它能夠減少程式的最長停頓時間。
Sun JDK提供的HotSpot JVM就能支援增量式GC。HotSpot JVM預設GC方式為不使用增量GC,為了啟動增量GC,我們必須在執行Java程式時增加-Xincgc的引數。HotSpot JVM增量式GC的實現是採用Train GC演算法。它的基本想法就是,將堆中的所有物件按照建立和使用情況進行分組(分層),將使用頻繁高和具有相關性的物件放在一隊中,隨著程式的執行,不斷對組進行調整。當GC執行時,它總是先回收最老的(最近很少訪問的)的物件,如果整組都為可回收物件,GC將整組回收。這樣,每次GC執行只回收一定比例的不可達物件,保證程式的順暢執行。
詳解finalize函式
finalize是位於Object類的一個方法,該方法的訪問修飾符為protected,由於所有類為Object的子類,因此使用者類很容易訪問到這個方法。由於,finalize函式沒有自動實現鏈式呼叫,我們必須手動的實現,因此finalize函式的最後一個語句通常是super.finalize()。透過這種方式,我們可以實現從下到上實現finalize的呼叫,即先釋放自己的資源,然後再釋放父類的資源。
根據Java語言規範,JVM保證呼叫finalize函式之前,這個物件是不可達的,但是JVM不保證這個函式一定會被呼叫。另外,規範還保證finalize函式最多執行一次。
很多Java初學者會認為這個方法類似與C++中的解構函式,將很多物件、資源的釋放都放在這一函式里面。其實,這不是一種很好的方式。原因有三,其一,GC為了能夠支援finalize函式,要對覆蓋這個函式的物件作很多附加的工作。其二,在finalize執行完成之後,該物件可能變成可達的,GC還要再檢查一次該物件是否是可達的。因此,使用finalize會降低GC的執行效能。其三,由於GC呼叫finalize的時間是不確定的,因此透過這種方式釋放資源也是不確定的。
通常,finalize用於一些不容易控制、並且非常重要資源的釋放,例如一些I/O的操作,資料的連線。這些資源的釋放對整個應用程式是非常關鍵的。在這種情況下,程式設計師應該以透過程式本身管理(包括釋放)這些資源為主,以finalize函式釋放資源方式為輔,形成一種雙保險的管理機制,而不應該僅僅依靠finalize來釋放資源。
GC的基本原理
Java的記憶體管理實際上就是物件的管理,其中包括物件的分配和釋放。
對於程式設計師來說,分配物件使用new關鍵字;釋放物件時,只要將物件所有引用賦值為null,讓程式不能夠再訪問到這個物件,我們稱該物件為"不可達的"。GC將負責回收所有"不可達"物件的記憶體空間。
對於GC來說,當程式設計師建立物件時,GC就開始監控這個物件的地址、大小以及使用情況。通常,GC採用有向圖的方式記錄和管理堆(heap)中的所有物件(詳見 參考資料1 )。透過這種方式確定哪些物件是"可達的",哪些物件是"不可達的"。當GC確定一些物件為"不可達"時,GC就有責任回收這些記憶體空間。但是,為了保證GC能夠在不同平臺實現的問題,Java規範對GC的很多行為都沒有進行嚴格的規定。例如,對於採用什麼型別的回收演算法、什麼時候進行回收等重要問題都沒有明確的規定。因此,不同的JVM的實現者往往有不同的實現演算法。這也給Java程式設計師的開發帶來行多不確定性。本文研究了幾個與GC工作相關的問題,努力減少這種不確定性給Java程式帶來的負面影響。
增量式GC( Incremental GC )
GC在JVM中通常是由一個或一組程式來實現的,它本身也和使用者程式一樣佔用heap空間,執行時也佔用CPU。當GC程式執行時,應用程式停止執行。因此,當GC執行時間較長時,使用者能夠感到Java程式的停頓,另外一方面,如果GC執行時間太短,則可能物件回收率太低,這意味著還有很多應該回收的物件沒有被回收,仍然佔用大量記憶體。因此,在設計GC的時候,就必須在停頓時間和回收率之間進行權衡。一個好的GC實現允許使用者定義自己所需要的設定,例如有些記憶體有限有裝置,對記憶體的使用量非常敏感,希望GC能夠準確的回收記憶體,它並不在意程式速度的放慢。另外一些實時網路遊戲,就不能夠允許程式有長時間的中斷。增量式GC就是透過一定的回收演算法,把一個長時間的中斷,劃分為很多個小的中斷,透過這種方式減少GC對使用者程式的影響。雖然,增量式GC在整體效能上可能不如普通GC的效率高,但是它能夠減少程式的最長停頓時間。
Sun JDK提供的HotSpot JVM就能支援增量式GC。HotSpot JVM預設GC方式為不使用增量GC,為了啟動增量GC,我們必須在執行Java程式時增加-Xincgc的引數。HotSpot JVM增量式GC的實現是採用Train GC演算法。它的基本想法就是,將堆中的所有物件按照建立和使用情況進行分組(分層),將使用頻繁高和具有相關性的物件放在一隊中,隨著程式的執行,不斷對組進行調整。當GC執行時,它總是先回收最老的(最近很少訪問的)的物件,如果整組都為可回收物件,GC將整組回收。這樣,每次GC執行只回收一定比例的不可達物件,保證程式的順暢執行。
詳解finalize函式
finalize是位於Object類的一個方法,該方法的訪問修飾符為protected,由於所有類為Object的子類,因此使用者類很容易訪問到這個方法。由於,finalize函式沒有自動實現鏈式呼叫,我們必須手動的實現,因此finalize函式的最後一個語句通常是super.finalize()。透過這種方式,我們可以實現從下到上實現finalize的呼叫,即先釋放自己的資源,然後再釋放父類的資源。
根據Java語言規範,JVM保證呼叫finalize函式之前,這個物件是不可達的,但是JVM不保證這個函式一定會被呼叫。另外,規範還保證finalize函式最多執行一次。
很多Java初學者會認為這個方法類似與C++中的解構函式,將很多物件、資源的釋放都放在這一函式里面。其實,這不是一種很好的方式。原因有三,其一,GC為了能夠支援finalize函式,要對覆蓋這個函式的物件作很多附加的工作。其二,在finalize執行完成之後,該物件可能變成可達的,GC還要再檢查一次該物件是否是可達的。因此,使用finalize會降低GC的執行效能。其三,由於GC呼叫finalize的時間是不確定的,因此透過這種方式釋放資源也是不確定的。
通常,finalize用於一些不容易控制、並且非常重要資源的釋放,例如一些I/O的操作,資料的連線。這些資源的釋放對整個應用程式是非常關鍵的。在這種情況下,程式設計師應該以透過程式本身管理(包括釋放)這些資源為主,以finalize函式釋放資源方式為輔,形成一種雙保險的管理機制,而不應該僅僅依靠finalize來釋放資源。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10901326/viewspace-965617/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 學習Java:垃圾回收與程式設計Java程式設計
- PHP垃圾收集器和程式設計師的幽默PHP程式設計師
- java垃圾收集器與記憶體分配策略Java記憶體
- java8預設使用的垃圾收集器Java
- 理解Java記憶體區域與垃圾收集器Java記憶體
- java幾種垃圾收集方法和垃圾收集器Java
- Java G1 垃圾收集器Java
- Java虛擬機器學習 - 垃圾收集器Java虛擬機機器學習
- 垃圾收集器與記憶體分配策略_hotspot垃圾收集演算法實現和垃圾收集器記憶體HotSpot演算法
- Java虛擬機器04——垃圾收集器Java虛擬機
- java中各種垃圾收集器的原理Java
- 好程式設計師Java培訓分享Java教程垃圾回收與演算法程式設計師Java演算法
- 垃圾收集器與記憶體分配策略記憶體
- JVM——垃圾收集器與記憶體分配JVM記憶體
- 垃圾收集器:引用計數演算法演算法
- Java新的Z垃圾收集器ZGC介紹JavaGC
- 一張圖提示如何選擇Java垃圾收集器?Java
- 深入理解 Java G1 垃圾收集器Java
- JVM虛擬機器-垃圾回收機制與垃圾收集器概述JVM虛擬機
- 垃圾收集器與記憶體分配策略_垃圾收集演算法記憶體演算法
- JVM 垃圾收集器與記憶體分配策略JVM記憶體
- JVM垃圾收集器(八)JVM
- 垃圾收集器學習
- Java虛擬機器詳解(四)------垃圾收集器Java虛擬機
- jvm系列(三):java GC演算法 垃圾收集器JVMJavaGC演算法
- JVM(3)-垃圾收集器與記憶體分配策略JVM記憶體
- JVM-垃圾收集器與記憶體分配策略JVM記憶體
- 深入學習Java虛擬機器——垃圾收集器與記憶體分配策略Java虛擬機記憶體
- 深入理解Java虛擬機器 - 垃圾收集器與記憶體分配策略Java虛擬機記憶體
- 深入理解Java虛擬機器-垃圾收集器與記憶體分配策略Java虛擬機記憶體
- JVM垃圾收集器總結JVM
- JVM垃圾收集器專題JVM
- JVM 經典垃圾收集器JVM
- 深入理解java虛擬機器之垃圾收集器Java虛擬機
- JVM 初探:記憶體分配、GC 原理與垃圾收集器JVM記憶體GC
- 《Java8函數語言程式設計》讀書筆記---收集器Java函數程式設計筆記
- GC 分代回收 - 垃圾收集器GC
- JVM(五)-垃圾收集器入門JVM