小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

JVM的GC調優(yōu)

 dongsibei 2014-04-23

誰需要GC調優(yōu)

小規(guī)模程序,垃圾收集算法能很好的工作。因為里面的對象圖不大,所以收集代價不高。但是如果是大規(guī)模的程序,對象成百上千,一次遍歷,就算是復制收集器中只對活動對象的遍歷,都需要很長的時間。所以,大規(guī)模程序,有必要深入了解GC的工作方式,了解和調整GC的參數。

關于串行和并行GC收集算法

在JVM 1.3.1以前,只有串行收集器,沒有并行收集器,對于多處理器,系統(tǒng)吞吐量損失很大。見下圖。為此,1.3.1以后(不包含1.3.1),引入了并發(fā)GC收集算法。
JVM1.4.2上,有4種垃圾收集器,默認會選擇串行收集器。
JVM5.0后,則會根據用戶機器的類型自動選擇收集器。

1% GC 中的 1%是指,在一個CPU上執(zhí)行且只花1%的CPU時間做垃圾收集的應用程序。
可以看到,當這個程序在處理器為30個以上的系統(tǒng)上運行,系統(tǒng)的吞吐量會下降到80%以下,即本來在單CPU系統(tǒng)上只花1%時間做搜集的程序會在30個以上CPU的系統(tǒng)上,花上20%的時間做收集。

為什么會這樣呢?因為單CPU收集算法在多CPU系統(tǒng)上面做收集的時候,GC算法會暫停運行在任何CPU上面的程序,而自己卻只能利用一個CPU做GC,所以造成了這種情況。

代Generation

自從JVM1.2以后,Sun采用了一種分代收集的策略,即將堆分成3個不同的區(qū)域,按照對象存活的時間的不同,將對象保存在不同的堆上。在不同的代上面,應用不同的收集算法,來達到最優(yōu)化收集。

這3個區(qū)域叫年輕代,年老代和持久代。
除Class和Method等元數據在持久代上面分配以外,所有的對象都在年輕代上面分配,當達到一定的條件,如經過在年輕代上面N次收集后的對象,就會保存到年老代之中。

在年輕代上面進行的收集叫Minor collections,在年輕代和年老代上面同時收集叫Major collections。

Tips:

盡量不要調用System.gc(),因為這會觸發(fā)Major collections。Major collections的收集效率不高,因為它要遍歷幾乎所有的對象。
沒有辦法利用API直接觸發(fā)Minor collections,但是仍然有其他的調優(yōu)手段。當使用完集合對象后,把引用設置為null,這樣避免gc在收集過程中,無謂地遍歷那些即將就要釋放的對象。

實驗表明,年輕代上面的對象98%的對象都會在短時間內死亡,故Minor collections可以利用拷貝收集器,只遍歷那些2%存活的對象,而不用管那些死亡的對象,來提高收集效率。

為了讓Minor collections能充分利用年輕代上面對象大量死亡的這個特點,就需要調整以下幾個參數:
1. 收集的頻率
過于頻繁的收集,會導致代中對象死亡率不夠高,從而需要遍歷這個代中大部分的對象,使得高死亡率這個條件利用的不充分。

2. 年輕代(堆)的大小
如果堆太小,一旦堆被占滿,Minor collections就不得不頻繁的啟動,導致情況1的發(fā)生,從而降低收集效率。

下圖反應了絕大多數對象在早起死亡的這一個事實:

從圖中可以看到,隨著時間的推進,大部分分配的字節(jié)都被回收了,少部分留了下來。被回收的這些字節(jié),就是所謂的die young,留下的則是live longer。

Bytes allocated 已經分配的總字節(jié)數
Bytes Surviving 存活的字節(jié)數
Minor Collections 對年輕代進行收集
Major Collections 對所有代進行收集

下圖描述了JVM中對堆的劃分:

Young 年輕代
Tenured 年老代
Perm 持久代

Virutal是指保留,而未分配的內存。如Perm中,加上Virtual則是Perm區(qū)域最大的大小,而剛開始并不會完全分配這個堆,只會按照最小的大小分配。

Young部分,被分為了三個部分,一個Eden,和兩個大小相同的Survivor。
所有的新建對象都會在Eden中分配,當Eden占滿后,即剩余的大小不足以分配新的對象時,就會觸發(fā)Minor collections。對Young收集時,會將對象拷貝到其中一個Survivor,另外一個Survivor保留不用。當下次收集時,則將上次Survivor中和Eden中的活動對象,拷貝到未用的Survivor中。如此反復。當某些對象經歷足夠長的次數或者時間后,就會被拷貝入年老代。

如果對Young的minor collections收集到的活動對象,survivor無法完全容納,則會將某些對象拷貝到年老代,如果年老代也不能容納新拷貝入的對象,則觸發(fā)Major collections。如果Major collections后,如果還不足以容納,就會將Virutal中預留的空間用來擴展已有的堆。當保留Virutal分配完畢后,仍然不足時,就會拋出OutOfMemory的錯誤。

Tips:

不要把年老代設置的過小,一般最好能比eden+survivor更大一些,這樣可以避免觸發(fā)Major collections。在這個前提下,年輕代越大越好。由于Young的eden區(qū)域是拷貝收集,容易產生碎片,所以此區(qū)域越大,越不容易導致因為碎片導致的內存不足而引發(fā)的minor collections。至于survivor,則要根據情況調整。過大的survior會造成浪費,過小的survior會導致,對象被直接拷貝到年老代。

JVM1.2中,未使用上面一大二小的結構,而是將Young分成兩個相同大小的區(qū)域,來回進行拷貝。

調整GC的手段


如何看懂上面那張圖:

行,分別對應了三個代
列,分別對應了實時性要求比較高的默認的和可調節(jié)的選項, 以及對吞吐量比較高的默認的和可調節(jié)的選項,還有就是調整這3個堆的選項。

-Xmx 調整JVM啟動時,保留Total Size的大小
-Xms 調整JVM啟動初始化時,Total Size的大小

每一次收集后,都會根據以下兩個參數調整Total Size的大小

-XX:MinHeapFreeRatio(默認,40)     Total Size中可用空間小于這個比率,就會擴展堆的大小,保持這個值
-XX:MaxHeapFreeRatio(默認,70)     Total Size中可用空間大于這個比例,就縮小堆的大小,保持這個值

Tips:

如果你的程序是服務器,那么通過將-Xmx和-Xms設置成相近,或者相同,可以阻止這種堆大小的頻繁調整,造成的不必要的收集和堆增長過程。

-XX:NewRatio=3     年老代和年輕代的內存分配比率,3表示,在Total Size中,年輕代占1份,年老代3份
-XX:NewSize           年輕代初始化時的大小
-XX:MaxNewSize     如果不指定,那么年輕代可以增長不受限制,但受NewRatio的限制
-XX:SurvivorRato=6 年輕代中,eden與survivor的比率,這里eden占6份,2個survivor占2份
-XX:MaxTenuringThreshold=0 閥值,超過這個閥值的對象將被拷貝到年老代

如何進行GC調優(yōu)?

1.性能的幾個重要度量參數

Troughput     吞吐量,除掉GC所用的時間后,真正執(zhí)行程序所在總時間的百分比
Pauses          暫停時間,即由于正在做GC,而沒有響應的那些時間
Footprint        內存需求,通常用page和cache line的數量來衡量

2.查看當前的GC收集

java命令運行時,輸入 -verbose:gc 參數

[GC 4802K->4383K(5312K), 0.0078566 secs]         //執(zhí)行了Minor collections
[Full GC 4383K->4383K(5312K), 0.0385521 secs]   //執(zhí)行了Major collections
[GC 5248K->4814K(8216K), 0.0121798 secs]         //空間仍然不夠,擴展了年輕代和年老代的空間

以第一行為例

GC                       表示執(zhí)行了Minor collections
4802K->4383K    表示GC執(zhí)行前和執(zhí)行后,堆中活動對象的大小
(5312K)               表示總的堆的大?。ú凰愠志么?,而且只算2個Survivor中的1個,即用戶可用堆的大?。?br>0.0078566 secs   表示GC所用的時間。主要,也是首先看這個,然后再看GC/Full GC是否過于頻繁。

這個信息反應了什么?年輕代太小,因為執(zhí)行了Minor collections之后,活動的對象并沒有顯著減少,4802K->4383K, 說明初始堆分配的不夠大。這個GC顯然是因為eden內部碎片導致的。

用-XX:+PrintGCDetails 參數,打印更詳細的信息

[GC [DefNew: 64575K->959K(64576K), 0.0457646 secs] 196016K->133633K(261184K), 0.0459067 secs]]

// Minor collections從年輕代64575K中收集到了959K的活動對象,花費了4微秒多一點
DefNew: 64575K->959K(64576K), 0.0457646 secs

//整個堆整理后,從196016K中,收集到了133633K的活動對象
196016K->133633K(261184K)

還可以用-XX:+PrintGCTimeStamps 查看帶起始和終止時間戳的信息

還有-XX:-PrintTenuringDistribution   打印出對象在放入年老代之前在年輕代做了多少次復制,如果復制次數過少,說明年輕代過小。

2類收集器

The Throughput Collector       以提高吞吐量,降低GC時間比的收集策略
The Concurrent Low Pause Collector      以提高暫停時間,以實時性為目的的收集策略

具體請看資料[1]中的內容。

其他

關于,如何遍歷年輕代中的活動對象的技術,請看資料[3]。

參考資料:

1.Tuning Garbage Collection with the 5.0 Java[tm] Virtual Machine
http://java./docs/hotspot/gc5.0/gc_tuning_5.html

2.Garbage Collector Ergonomics
http://java./j2se/1.5.0/docs/guide/vm/gc-ergonomics.html

3.JVM1.4.1中的垃圾收集
http://www.ibm.com/developerworks/cn/java/j-jtp11253/

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發(fā)現有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多