java垃圾的自動收集
當垃圾收集器判斷已經沒有任何引用指向物件的時候,會呼叫物件的finalize方法來釋放物件佔據的記憶體空間~
java中垃圾回收以前聽老師講好像是記憶體滿了他才去做一次整體垃圾回收,在回收垃圾的同時會呼叫finalize方法.你在構造一個類時可以構造一個類時覆蓋他的finalize方法以便於該類在被垃圾回收時執行一些程式碼,比如釋放資源.
1.JVM的gc概述
gc即垃圾收集機制是指jvm用於釋放那些不再使用的物件所佔用的記憶體。java語言並不要求jvm有gc,也沒有規定gc如何工作。不過常用的jvm都有gc,而且大多數gc都使用類似的演算法管理記憶體和執行收集操作。
在充分理解了垃圾收集演算法和執行過程後,才能有效的優化它的效能。有些垃圾收集專用於特殊的應用程式。比如,實時應用程式主要是為了避免垃圾收集中斷,而大多數OLTP應用程式則注重整體效率。理解了應用程式的工作負荷和jvm支援的垃圾收集演算法,便可以進行優化配置垃圾收集器。
垃圾收集的目的在於清除不再使用的物件。gc通過確定物件是否被活動物件引用來確定是否收集該物件。gc首先要判斷該物件是否是時候可以收集。兩種常用的方法是引用計數和物件引用遍歷。
1.1.引用計數
引用計數儲存對特定物件的所有引用數,也就是說,當應用程式建立引用以及引用超出範圍時,jvm必須適當增減引用數。當某物件的引用數為0時,便可以進行垃圾收集。
1.2.物件引用遍歷
早期的jvm使用引用計數,現在大多數jvm採用物件引用遍歷。物件引用遍歷從一組物件開始,沿著整個物件圖上的每條連結,遞迴確定可到達(reachable)的物件。如果某物件不能從這些根物件的一個(至少一個)到達,則將它作為垃圾收集。在物件遍歷階段,gc必須記住哪些物件可以到達,以便刪除不可到達的物件,這稱為標記(marking)物件。
下一步,gc要刪除不可到達的物件。刪除時,有些gc只是簡單的掃描堆疊,刪除未標記的未標記的物件,並釋放它們的記憶體以生成新的物件,這叫做清除(sweeping)。這種方法的問題在於記憶體會分成好多小段,而它們不足以用於新的物件,但是組合起來卻很大。因此,許多gc可以重新組織記憶體中的物件,並進行壓縮(compact),形成可利用的空間。
為此,gc需要停止其他的活動活動。這種方法意味著所有與應用程式相關的工作停止,只有gc執行。結果,在響應期間增減了許多混雜請求。另外,更復雜的 gc不斷增加或同時執行以減少或者清除應用程式的中斷。有的gc使用單執行緒完成這項工作,有的則採用多執行緒以增加效率。
2.幾種垃圾回收機制
2.1.標記-清除收集器
這種收集器首先遍歷物件圖並標記可到達的物件,然後掃描堆疊以尋找未標記物件並釋放它們的記憶體。這種收集器一般使用單執行緒工作並停止其他操作。
2.2.標記-壓縮收集器
有時也叫標記-清除-壓縮收集器,與標記-清除收集器有相同的標記階段。在第二階段,則把標記物件複製到堆疊的新域中以便壓縮堆疊。這種收集器也停止其他操作。
2.3.複製收集器
這種收集器將堆疊分為兩個域,常稱為半空間。每次僅使用一半的空間,jvm生成的新物件則放在另一半空間中。gc執行時,它把可到達物件複製到另一半空間,從而壓縮了堆疊。這種方法適用於短生存期的物件,持續複製長生存期的物件則導致效率降低。
2.4.增量收集器
增量收集器把堆疊分為多個域,每次僅從一個域收集垃圾。這會造成較小的應用程式中斷。
2.5.分代收集器
這種收集器把堆疊分為兩個或多個域,用以存放不同壽命的物件。jvm生成的新物件一般放在其中的某個域中。過一段時間,繼續存在的物件將獲得使用期並轉入更長壽命的域中。分代收集器對不同的域使用不同的演算法以優化效能。
2.6.併發收集器
併發收集器與應用程式同時執行。這些收集器在某點上(比如壓縮時)一般都不得不停止其他操作以完成特定的任務,但是因為其他應用程式可進行其他的後臺操作,所以中斷其他處理的實際時間大大降低。
2.7.並行收集器
並行收集器使用某種傳統的演算法並使用多執行緒並行的執行它們的工作。在多cpu機器上使用多執行緒技術可以顯著的提高java應用程式的可擴充套件性。
3.Sun HotSpot
1.4.1 JVM堆大小的調整
Sun HotSpot 1.4.1使用分代收集器,它把堆分為三個主要的域:新域、舊域以及永久域。Jvm生成的所有新物件放在新域中。一旦物件經歷了一定數量的垃圾收集迴圈後,便獲得使用期並進入舊域。在永久域中jvm則儲存class和method物件。就配置而言,永久域是一個獨立域並且不認為是堆的一部分。
下面介紹如何控制這些域的大小。可使用-Xms和-Xmx 控制整個堆的原始大小或最大值。
下面的命令是把初始大小設定為128M:
java –Xms128m
–Xmx256m為控制新域的大小,可使用-XX:NewRatio設定新域在堆中所佔的比例。
下面的命令把整個堆設定成128m,新域比率設定成3,即新域與舊域比例為1:3,新域為堆的1/4或32M:
java –Xms128m –Xmx128m –XX:NewRatio =3可使用-XX:NewSize和-XX:MaxNewsize設定新域的初始值和最大值。
下面的命令把新域的初始值和最大值設定成64m:
java –Xms256m –Xmx256m –Xmn64m
永久域預設大小為4m。執行程式時,jvm會調整永久域的大小以滿足需要。每次調整時,jvm會對堆進行一次完全的垃圾收集。
使用-XX:MaxPerSize標誌來增加永久域搭大小。在WebLogic Server應用程式載入較多類時,經常需要增加永久域的最大值。當jvm載入類時,永久域中的物件急劇增加,從而使jvm不斷調整永久域大小。為了避免調整,可使用-XX:PerSize標誌設定初始值。
下面把永久域初始值設定成32m,最大值設定成64m。
java -Xms512m -Xmx512m -Xmn128m -XX:PermSize=32m -XX:MaxPermSize=64m
預設狀態下,HotSpot在新域中使用複製收集器。該域一般分為三個部分。第一部分為Eden,用於生成新的物件。另兩部分稱為救助空間,當Eden 充滿時,收集器停止應用程式,把所有可到達物件複製到當前的from救助空間,一旦當前的from救助空間充滿,收集器則把可到達物件複製到當前的to救助空間。From和to救助空間互換角色。維持活動的物件將在救助空間不斷複製,直到它們獲得使用期並轉入舊域。使用-XX:SurvivorRatio 可控制新域子空間的大小。
同NewRation一樣,SurvivorRation規定某救助域與Eden空間的比值。比如,以下命令把新域設定成64m,Eden佔32m,每個救助域各佔16m:
java -Xms256m -Xmx256m -Xmn64m -XX:SurvivorRation =2
如前所述,預設狀態下HotSpot對新域使用複製收集器,對舊域使用標記-清除-壓縮收集器。在新域中使用複製收集器有很多意義,因為應用程式生成的大部分物件是短壽命的。理想狀態下,所有過渡物件在移出Eden空間時將被收集。如果能夠這樣的話,並且移出Eden空間的物件是長壽命的,那麼理論上可以立即把它們移進舊域,避免在救助空間反覆複製。但是,應用程式不能適合這種理想狀態,因為它們有一小部分中長壽命的物件。最好是保持這些中長壽命的物件並放在新域中,因為複製小部分的物件總比壓縮舊域廉價。為控制新域中物件的複製,可用-XX:TargetSurvivorRatio控制救助空間的比例(該值是設定救助空間的使用比例。如救助空間位1M,該值50表示可用500K)。該值是一個百分比,預設值是50。當較大的堆疊使用較低的 sruvivorratio時,應增加該值到80至90,以更好利用救助空間。用-XX:maxtenuring threshold可控制上限。
為放置所有的複製全部發生以及希望物件從eden擴充套件到舊域,可以把MaxTenuring Threshold設定成0。設定完成後,實際上就不再使用救助空間了,因此應把SurvivorRatio設成最大值以最大化Eden空間,設定如下:
java … -XX:MaxTenuringThreshold=0 –XX:SurvivorRatio=50000 …
4.BEA JRockit JVM的使用
Bea WebLogic 8.1使用的新的JVM用於Intel平臺。在Bea安裝完畢的目錄下可以看到有一個類似於jrockit81sp1_141_03的資料夾。這就是 Bea新JVM所在目錄。不同於HotSpot把Java位元組碼編譯成本地碼,它預先編譯成類。JRockit還提供了更細緻的功能用以觀察JVM的執行狀態,主要是獨立的GUI控制檯(只能適用於使用Jrockit才能使用jrockit81sp1_141_03自帶的console監控一些cpu及 memory引數)或者WebLogic Server控制檯。
Bea JRockit JVM支援4種垃圾收集器:
4.1.1.分代複製收集器
它與預設的分代收集器工作策略類似。物件在新域中分配,即JRockit文件中的nursery。這種收集器最適合單cpu機上小型堆操作。
4.1.2.單空間併發收集器
該收集器使用完整堆,並與背景執行緒共同工作。儘管這種收集器可以消除中斷,但是收集器需花費較長的時間尋找死物件,而且處理應用程式時收集器經常執行。如果處理器不能應付應用程式產生的垃圾,它會中斷應用程式並關閉收集。
分代併發收集器這種收集器在護理域使用排它複製收集器,在舊域中則使用併發收集器。由於它比單空間共同發生收集器中斷頻繁,因此它需要較少的記憶體,應用程式的執行效率也較高,注意,過小的護理域可以導致大量的臨時物件被擴充套件到舊域中。這會造成收集器超負荷運作,甚至採用排它性工作方式完成收集。
4.1.3.並行收集器
該收集器也停止其他程序的工作,但使用多執行緒以加速收集程序。儘管它比其他的收集器易於引起長時間的中斷,但一般能更好的利用記憶體,程式效率也較高。
預設狀態下,JRockit使用分代併發收集器。要改變收集器,可使用-Xgc:,對應四個收集器分別為 gencopy,singlecon,gencon以及parallel。可使用-Xms和-Xmx設定堆的初始大小和最大值。要設定護理域,則使用- Xns:java –jrockit –Xms512m –Xmx512m –Xgc:gencon –Xns128m…儘管JRockit支援-verbose:gc開關,但它輸出的資訊會因收集器的不同而異。JRockit還支援memory、 load和codegen的輸出。
注意 :如果 使用JRockit JVM的話還可以使用WLS自帶的console(C:\bea\jrockit81sp1_141_03\bin下)來監控一些資料,如cpu, memery等。要想能構監控必須在啟動服務時startWeblogic.cmd中加入-Xmanagement引數。
5.如何從JVM中獲取資訊來進行調整
-verbose.gc開關可顯示gc的操作內容。開啟它,可以顯示最忙和最空閒收集行為發生的時間、收集前後的記憶體大小、收集需要的時間等。開啟- xx:+ printgcdetails開關,可以詳細瞭解gc中的變化。開啟-XX: + PrintGCTimeStamps開關,可以瞭解這些垃圾收集發生的時間,自jvm啟動以後以秒計量。最後,通過-xx: + PrintHeapAtGC開關了解堆的更詳細的資訊。為了瞭解新域的情況,可以通過-XX:=PrintTenuringDistribution開關了解獲得使用期的物件權。
6.Pdm系統JVM調整
6.1.伺服器:前提記憶體1G 單CPU
可通過如下引數進行調整:-server 啟用伺服器模式(如果CPU多,伺服器機建議使用此項)
-Xms,-Xmx一般設為同樣大小。 800m
-Xmn 是將NewSize與MaxNewSize設為一致。320m
-XX:PerSize 64m
-XX:NewSize 320m 此值設大可調大新物件區,減少Full GC次數
-XX:MaxNewSize 320m
-XX:NewRato NewSize設了可不設。
-XX: SurvivorRatio
-XX:userParNewGC 可用來設定並行收集
-XX:ParallelGCThreads 可用來增加並行度
-XXUseParallelGC 設定後可以使用並行清除收集器
-XX:UseAdaptiveSizePolicy 與上面一個聯合使用效果更好,利用它可以自動優化新域大小以及救助空間比值
6.2.客戶機:通過在JNLP檔案中設定引數來調整客戶端JVM
JNLP中引數:initial-heap-size和max-heap-size
這可以在framework的RequestManager中生成JNLP檔案時加入上述引數,但是這些值是要求根據客戶機的硬體狀態變化的(如客戶機的記憶體大小等)。建議這兩個引數值設為客戶機可用記憶體的60%(有待測試)。為了在動態生成JNLP時以上兩個引數值能夠隨客戶機不同而不同,可靠慮獲得客戶機系統資訊並將這些嵌到首頁index.jsp中作為連線請求的引數。
在設定了上述引數後可以通過Visualgc 來觀察垃圾回收的一些引數狀態,再做相應的調整來改善效能。一般的標準是減少fullgc的次數,最好硬體支援使用並行垃圾回收(要求多CPU)