JVM的gc概述 gc即垃圾收集機制是指jvm用於釋放那些不再使用的對象所占用的內存
java語言並不要求jvm有gc
也沒有規定gc如何工作
不過常用的jvm都有gc
而且大多數gc都使用類似的算法管理內存和執行收集操作
在充分理解了垃圾收集算法和執行過程後
才能有效的優化它的性能
有些垃圾收集專用於特殊的應用程序
比如
實時應用程序主要是為了避免垃圾收集中斷
而大多數OLTP應用程序則注重整體效率
理解了應用程序的工作負荷和jvm支持的垃圾收集算法
便可以進行優化配置垃圾收集器
垃圾收集的目的在於清除不再使用的對象
gc通過確定對象是否被活動對象引用來確定是否收集該對象
gc首先要判斷該對象是否是時候可以收集
兩種常用的方法是引用計數和對象引用遍歷
引用計數
引用計數存儲對特定對象的所有引用數
也就是說
當應用程序創建引用以及引用超出范圍時
jvm必須適當增減引用數
當某對象的引用數為
時
便可以進行垃圾收集
對象引用遍歷
早期的jvm使用引用計數
現在大多數jvm采用對象引用遍歷
對象引用遍歷從一組對象開始
沿著整個對象圖上的每條鏈接
遞歸確定可到達(reachable)的對象
如果某對象不能從這些根對象的一個(至少一個)到達
則將它作為垃圾收集
在對象遍歷階段
gc必須記住哪些對象可以到達
以便刪除不可到達的對象
這稱為標記(marking)對象
下一步
gc要刪除不可到達的對象
刪除時
有些gc只是簡單的掃描堆棧
刪除未標記的未標記的對象
並釋放它們的內存以生成新的對象
這叫做清除(sweeping)
這種方法的問題在於內存會分成好多小段
而它們不足以用於新的對象
但是組合起來卻很大
因此
許多gc可以重新組織內存中的對象
並進行壓縮(compact)
形成可利用的空間
為此
gc需要停止其他的活動活動
這種方法意味著所有與應用程序相關的工作停止
只有gc運行
結果
在響應期間增減了許多混雜請求
另外
更復雜的 gc不斷增加或同時運行以減少或者清除應用程序的中斷
有的gc使用單線程完成這項工作
有的則采用多線程以增加效率
幾種垃圾回收機制 標記-清除收集器
這種收集器首先遍歷對象圖並標記可到達的對象
然後掃描堆棧以尋找未標記對象並釋放它們的內存
這種收集器一般使用單線程工作並停止其他操作
標記-壓縮收集器
有時也叫標記-清除-壓縮收集器
與標記-清除收集器有相同的標記階段
在第二階段
則把標記對象復制到堆棧的新域中以便壓縮堆棧
這種收集器也停止其他操作
復制收集器
這種收集器將堆棧分為兩個域
常稱為半空間
每次僅使用一半的空間
jvm生成的新對象則放在另一半空間中
gc運行時
它把可到達對象復制到另一半空間
從而壓縮了堆棧
這種方法適用於短生存期的對象
持續復制長生存期的對象則導致效率降低
增量收集器
增量收集器把堆棧分為多個域
每次僅從一個域收集垃圾
這會造成較小的應用程序中斷
分代收集器
這種收集器把堆棧分為兩個或多個域
用以存放不同壽命的對象
jvm生成的新對象一般放在其中的某個域中
過一段時間
繼續存在的對象將獲得使用期並轉入更長壽命的域中
分代收集器對不同的域使用不同的算法以優化性能
並發收集器
並發收集器與應用程序同時運行
這些收集器在某點上(比如壓縮時)一般都不得不停止其他操作以完成特定的任務
但是因為其他應用程序可進行其他的後台操作
所以中斷其他處理的實際時間大大降低
並行收集器
並行收集器使用某種傳統的算法並使用多線程並行的執行它們的工作
在多cpu機器上使用多線程技術可以顯著的提高java應用程序的可擴展性
Sun HotSpot JVM堆大小的調整
Sun HotSpot
使用分代收集器
它把堆分為三個主要的域
新域
舊域以及永久域
Jvm生成的所有新對象放在新域中
一旦對象經歷了一定數量的垃圾收集循環後
便獲得使用期並進入舊域
在永久域中jvm則存儲class和method對象
就配置而言
永久域是一個獨立域並且不認為是堆的一部分
下面介紹如何控制這些域的大小
可使用
Xms和
Xmx 控制整個堆的原始大小或最大值
下面的命令是把初始大小設置為
M
java –Xms
m
–Xmx
m為控制新域的大小
可使用
XX:NewRatio設置新域在堆中所占的比例
下面的命令把整個堆設置成
m
新域比率設置成
即新域與舊域比例為
新域為堆的
/
或
M
java –Xms
m –Xmx
m
–XX:NewRatio =
可使用
XX:NewSize和
XX:MaxNewsize設置新域的初始值和最大值
下面的命令把新域的初始值和最大值設置成
m:
java –Xms
m –Xmx
m –Xmn
m
永久域默認大小為
m
運行程序時
jvm會調整永久域的大小以滿足需要
每次調整時
jvm會對堆進行一次完全的垃圾收集
使用
XX:MaxPerSize標志來增加永久域搭大小
在WebLogic Server應用程序加載較多類時
經常需要增加永久域的最大值
當jvm加載類時
永久域中的對象急劇增加
從而使jvm不斷調整永久域大小
為了避免調整
可使用
XX:PerSize標志設置初始值
下面把永久域初始值設置成
m
最大值設置成
m
java
Xms
m
Xmx
m
Xmn
m
XX:PermSize=
m
XX:MaxPermSize=
m
默認狀態下
HotSpot在新域中使用復制收集器
該域一般分為三個部分
第一部分為Eden
用於生成新的對象
另兩部分稱為救助空間
當Eden 充滿時
收集器停止應用程序
把所有可到達對象復制到當前的from救助空間
一旦當前的from救助空間充滿
收集器則把可到達對象復制到當前的to救助空間
From和to救助空間互換角色
維持活動的對象將在救助空間不斷復制
直到它們獲得使用期並轉入舊域
使用
XX:SurvivorRatio 可控制新域子空間的大小
同NewRation一樣
SurvivorRation規定某救助域與Eden空間的比值
比如
以下命令把新域設置成
m
Eden占
m
每個救助域各占
m
java
Xms
m
Xmx
m
Xmn
m
XX:SurvivorRation =
如前所述
默認狀態下HotSpot對新域使用復制收集器
對舊域使用標記-清除-壓縮收集器
在新域中使用復制收集器有很多意義
因為應用程序生成的大部分對象是短壽命的
理想狀態下
所有過渡對象在移出Eden空間時將被收集
如果能夠這樣的話
並且移出Eden空間的對象是長壽命的
那麼理論上可以立即把它們移進舊域
避免在救助空間反復復制
但是
應用程序不能適合這種理想狀態
因為它們有一小部分中長壽命的對象
最好是保持這些中長壽命的對象並放在新域中
因為復制小部分的對象總比壓縮舊域廉價
為控制新域中對象的復制
可用
XX:TargetSurvivorRatio控制救助空間的比例(該值是設置救助空間的使用比例
如救助空間位
M
該值
表示可用
K)
該值是一個百分比
默認值是
當較大的堆棧使用較低的 sruvivorratio時
應增加該值到
至
以更好利用救助空間
用
XX:maxtenuring threshold可控制上限
為放置所有的復制全部發生以及希望對象從eden擴展到舊域
可以把MaxTenuring Threshold設置成
設置完成後
實際上就不再使用救助空間了
因此應把SurvivorRatio設成最大值以最大化Eden空間
設置如下
java …
XX:MaxTenuringThreshold=
–XX:SurvivorRatio=
…
BEA JRockit JVM的使用 Bea WebLogic
使用的新的JVM用於Intel平台
在Bea安裝完畢的目錄下可以看到有一個類似於jrockit
sp
_
_
的文件夾
這就是 Bea新JVM所在目錄
不同於HotSpot把Java字節碼編譯成本地碼
它預先編譯成類
JRockit還提供了更細致的功能用以觀察JVM的運行狀態
主要是獨立的GUI控制台(只能適用於使用Jrockit才能使用jrockit
sp
_
_
自帶的console監控一些cpu及 memory參數)或者WebLogic Server控制台
Bea JRockit JVM支持
種垃圾收集器
分代復制收集器
它與默認的分代收集器工作策略類似
對象在新域中分配
即JRockit文檔中的nursery
這種收集器最適合單cpu機上小型堆操作
單空間並發收集器
該收集器使用完整堆
並與背景線程共同工作
盡管這種收集器可以消除中斷
但是收集器需花費較長的時間尋找死對象
而且處理應用程序時收集器經常運行
如果處理器不能應付應用程序產生的垃圾
它會中斷應用程序並關閉收集
分代並發收集器這種收集器在護理域使用排它復制收集器
在舊域中則使用並發收集器
由於它比單空間共同發生收集器中斷頻繁
因此它需要較少的內存
應用程序的運行效率也較高
注意
過小的護理域可以導致大量的臨時對象被擴展到舊域中
這會造成收集器超負荷運作
甚至采用排它性工作方式完成收集
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26281.html