<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 42  文章 - 71  trackbacks - 0
    <2008年4月>
    303112345
    6789101112
    13141516171819
    20212223242526
    27282930123
    45678910

    常用鏈接

    留言簿

    隨筆檔案

    文章分類

    文章檔案

    搜索

    •  

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    Technorati 標(biāo)簽: ,,,

    Sun HotSpot JVM 1.4.2 調(diào)優(yōu)

    目錄

    1. 序言

    2. 虛擬機(jī)中的"代"

    2.1. 性能考慮

    2.2. 測(cè)量

    3. 調(diào)整代大小

    3.1. 堆的總體大小

    3.2. 新生代

    3.3. 新生代的保證

    4. 收集器類型

    4.1. 何時(shí)使用吞吐收集器

    4.2. 吞吐收集器

    4.2.1. 大小自適應(yīng)

    4.2.2. Aggressive堆

    4.2.3. 吞吐收集器的測(cè)量法

    4.3. 何時(shí)使用并發(fā)收集器

    4.4. 并發(fā)收集器

    4.4.1. 并發(fā)的額外開銷

    4.4.2. 新生代的保證

    4.4.3. 完全收集

    4.4.4. 漂浮垃圾

    4.4.5. 暫停

    4.4.6. 并發(fā)階段

    4.4.7. 并發(fā)收集的測(cè)量

    4.4.8. 并發(fā)收集器的并行次要收集

    4.5. 何時(shí)使用增量收集器

    4.6. 增量收集器

    4.6.1. 增量收集器測(cè)量

    5. 其他考慮事項(xiàng)

    6. 總結(jié)

    7. 其他文檔

    7.1. 輸出示例

    7.2. 常見問題


    1. 序言

    從小型桌面應(yīng)用到運(yùn)行在大型服務(wù)器的web服務(wù),Java 2平臺(tái)被廣泛的應(yīng)用。在1.4.1版本的J2SE平臺(tái)中,引入了2種新的垃圾收集器(garbage collector),現(xiàn)在總共有4種垃圾收集器供我們選擇。那么,應(yīng)該如何選擇垃圾收集器?又有哪些因素可以作為選擇的依據(jù)?本文檔描述了垃圾收集器共有的特征,并對(duì)于在單線程,stop-the-world的收集器上如何最大限度的利用這些特征給出了調(diào)整指導(dǎo)。最后,討論了其他3種收集器獨(dú)有的特征以及在4種垃圾收集器中做出選擇的一些標(biāo)準(zhǔn)。

    對(duì)于用戶而言,在什么情況下,垃圾收集器會(huì)帶來性能問題?對(duì)于大部分應(yīng)用來說,垃圾收集器不會(huì)帶來性能問題,也就是說,即使適垃圾收集器的運(yùn)行會(huì)帶來很短的暫停,但是應(yīng)用還是可以以令人滿意的性能運(yùn)行。但是對(duì)于使用了大量的線程、處理器、Socket以及內(nèi)存的大型應(yīng)用而言(使用默認(rèn)的垃圾收集器),情況就不同了。

    Amdahl 觀察到,大部分工作是無法很好的并行處理的,有些工作總是順序化的,所以,無法從并行機(jī)制中獲益。對(duì)于J2SE平臺(tái)來說,也是這樣,Java虛擬機(jī)從最初一直到1.3.1版本,都沒有并行的垃圾收集器,所以,相對(duì)于其他的并行應(yīng)用,垃圾收集器所帶來的性能影響在多處理器系統(tǒng)上會(huì)有所增長(zhǎng)。

    下圖描述的是一個(gè)具有良好彈性的理想系統(tǒng),如果不考慮垃圾收集的話。紅線表示在單處理器系統(tǒng)上的應(yīng)用,垃圾收集只占用1%的時(shí)間,當(dāng)遷移到有32個(gè)處理器的平臺(tái)上的時(shí)候,有超過20%的吞吐量(throughput)的損失;在單處理器系統(tǒng)上垃圾收集時(shí)間占10%的應(yīng)用(不考慮那些令人無法接受的垃圾收集時(shí)間),當(dāng)擴(kuò)展到32處理器系統(tǒng)上時(shí),吞吐量的損失超過了75%。

    這表明了,在開發(fā)小型應(yīng)用時(shí)可以忽略不計(jì)的速度問題,當(dāng)擴(kuò)展到大型應(yīng)用系統(tǒng)時(shí)卻成為最為突出的性能瓶頸。但是對(duì)于這種瓶頸的小小的改良就可能收獲性能上的顯著提高,所以,對(duì)于大型應(yīng)用來說,調(diào)整垃圾收集器是非常有價(jià)值的。

    對(duì)于大部分應(yīng)用來說,默認(rèn)的垃圾收集器都是可以滿足需要的。其他的幾種垃圾收集器因?yàn)橛幸恍┨厥獾男袨椋褂闷饋肀容^復(fù)雜。除非應(yīng)用有特殊需求,一般情況下建議選用默認(rèn)的垃圾收集器。當(dāng)然,也有例外情況,對(duì)于那些運(yùn)行在有大量?jī)?nèi)存和處理器的主機(jī)上的大型應(yīng)用,可以首先嘗試aggressive 堆(heap)選項(xiàng)(-XX:+AggressiveHeap),稍后有詳細(xì)描述。

    本文選用J2SE 1.4.2(Sun HotSpot),Sun Solaris操作系統(tǒng)(SPARC平臺(tái)版本),因?yàn)檫@個(gè)平臺(tái)對(duì)于硬件和軟件來說都有很好的擴(kuò)展性。當(dāng)然了,本文也適用于其他平臺(tái),如 Linux,Microsoft Windows, Sun Solaris(X86平臺(tái)版本)。盡管在不同平臺(tái)上虛擬機(jī)的命令行參數(shù)是一樣的,但是可能其他平臺(tái)上的默認(rèn)值和本文描述的有所差別。

    2. 虛擬機(jī)中的"代"

    J2SE平臺(tái)的一個(gè)特征就是它為開發(fā)人員實(shí)現(xiàn)了內(nèi)存的申請(qǐng)和釋放,但是,當(dāng)垃圾收集成為主要的性能瓶頸時(shí),我們就有必要對(duì)它的實(shí)現(xiàn)進(jìn)行深入的了解。垃圾收集器可以對(duì)應(yīng)用使用對(duì)象的方式進(jìn)行一個(gè)設(shè)定,反映在一些可調(diào)整的參數(shù)上,通過這些參數(shù),在保證抽象能力的前提下提升了虛擬機(jī)的性能。

    從運(yùn)行的程序中,沒有可以到達(dá)某一對(duì)象的指針,那么這個(gè)對(duì)象就被認(rèn)為是"垃圾"。最直截了當(dāng)?shù)睦占惴ň褪敲杜e每個(gè)可到達(dá)的對(duì)象,剩下的對(duì)象就是可以進(jìn)行回收的垃圾對(duì)象了。這種方案所消耗的時(shí)間和活動(dòng)對(duì)象的數(shù)量是成比例的,所以,對(duì)于要保持大量活動(dòng)對(duì)象的大型應(yīng)用,顯然是不適用的。

    從J2SE 1.2開始,虛擬機(jī)將幾種不同的垃圾收集算法組合在一起使用,就是"分代收集"(generational collection)。在幼兒收集器(naive garbage collection)檢查堆中活動(dòng)對(duì)象的同時(shí),分代收集器通過分析一些觀測(cè)屬性來避免額外的工作。

    在這些觀測(cè)屬性中最重要的就是幼兒死亡率(infant mortality)。下面圖表中的藍(lán)色區(qū)域就是對(duì)象存活期的典型分布。其中X軸表示對(duì)象的存活時(shí)間,在分配字節(jié)時(shí)測(cè)量。Y軸表示的是對(duì)應(yīng)存活時(shí)間的對(duì)象字節(jié)總量。左側(cè)的頂點(diǎn)表示對(duì)象可能在分配之后很短的時(shí)間內(nèi)就被回收,例如在循環(huán)中的枚舉對(duì)象,僅僅能夠存活一個(gè)循環(huán)。

    有些對(duì)象能夠存活很長(zhǎng)時(shí)間,所以上圖的X軸向右延展。例如那些在初始化時(shí)就創(chuàng)建并且能夠存活直到進(jìn)程終止的對(duì)象。在這兩個(gè)極端之間,就是一些只在中間計(jì)算才存活的對(duì)象,就是我們看到的到幼兒死亡率右側(cè)的區(qū)域。可能有些應(yīng)用的對(duì)象存活周期分布有些差異,但令人驚訝的是大部分應(yīng)用都和上圖吻合。通過關(guān)注主要的"夭折"(die young)對(duì)象來進(jìn)行垃圾收集是行之有效的。

    為了針對(duì)這種情況進(jìn)行優(yōu)化,所以將內(nèi)存進(jìn)行分代管理,也就是說內(nèi)存池保持不同年齡段的對(duì)象。在分代管理的內(nèi)存中,當(dāng)一個(gè)代被對(duì)象充滿的時(shí)候,就在這個(gè)代上進(jìn)行垃圾收集。對(duì)象是在新生代(young generation)區(qū)域中進(jìn)行分配,因?yàn)榇蟛糠謱?duì)象在這個(gè)代中就已經(jīng)死亡。當(dāng)新生代被填充滿之后,在其上進(jìn)行一次次要垃圾收集(minor collection),由于在新生代有很高的夭折率,所以次要收集算法針對(duì)這種情況進(jìn)行了優(yōu)化。這種收集的消耗和被其收集的對(duì)象的數(shù)量成比例。充滿死亡對(duì)象的新生代收集起來非常的快。一些仍然存活的對(duì)象被移動(dòng)到舊生代(tenured generation),當(dāng)舊生代需要進(jìn)行垃圾收集的時(shí)候,就會(huì)進(jìn)行主要垃圾收集(major collection),這種收集方式比起次要收集來要慢得多,因?yàn)樗婕傲巳康幕顒?dòng)對(duì)象。

    下圖顯示,次要收集的間隔時(shí)間比較長(zhǎng),這樣能夠確保大部分對(duì)象都已經(jīng)死亡。為了確保次要收集發(fā)生的間隔能夠足夠長(zhǎng),需要新生代有足夠的空間,這樣才能夠使得次要收集充分利用新生代中高夭折率的特點(diǎn)。對(duì)于那些對(duì)象存活周期分布比較奇特的應(yīng)用情況就不同了,還有,不合適的代大小設(shè)置也會(huì)使得在對(duì)象死亡之前就不得不進(jìn)行收集。

    默認(rèn)的垃圾收集器可以應(yīng)用在小型的和大型的應(yīng)用,但是它的默認(rèn)參數(shù)設(shè)置對(duì)于小型應(yīng)用更高效。對(duì)于很多服務(wù)器應(yīng)用來說,這些參數(shù)并不合適,這就引出了本文的中心原則:

    如果垃圾收集成為性能瓶頸,建議你調(diào)整代的大小參數(shù)。并檢查垃圾收集的輸出信息,研究性能對(duì)于垃圾收集參數(shù)的敏感度

    默認(rèn)的代配置如下圖所示:

    在初始化時(shí),虛擬機(jī)保持一個(gè)很大的地址空間,但并不真正的從物理內(nèi)存中申請(qǐng)(按需申請(qǐng))。用來存放對(duì)象的地址空間被劃分成兩部分:新生代和舊生代。

    新生代由一個(gè)Eden和兩個(gè)存活空間(survivor space)組成,對(duì)象在Eden中進(jìn)行創(chuàng)建和內(nèi)存分配。在任何時(shí)候,都有一個(gè)存活空間是空的,以用來容納從Eden和另外一個(gè)存活空間復(fù)制過來的活動(dòng)對(duì)象。對(duì)象以這種方式在兩個(gè)存活空間之間進(jìn)行復(fù)制,直到它存活時(shí)間較長(zhǎng)而被復(fù)制到舊生代。

    包括1.2版本的虛擬機(jī)(Solaris操作系統(tǒng))在內(nèi)的其他虛擬機(jī)產(chǎn)品,都是使用兩個(gè)大小相等的存活空間來進(jìn)行對(duì)象復(fù)制,而不是像圖中所示的一個(gè)Eden和兩個(gè)存活空間。這就意味著,通過調(diào)整新生代大小來調(diào)整性能并不總是具有可比性的。

    在舊生代中,有一部分比較特殊的,叫做持久代(permanent generation),它用來存放虛擬機(jī)自己的數(shù)據(jù),例如(class)和方法(method)。

    2.1. 性能考慮

    對(duì)于垃圾收集的性能,主要有兩個(gè)指標(biāo)。吞吐量(throughput)指用來進(jìn)行垃圾收集之外工作所用的時(shí)間占總時(shí)間的百分比,一般要通過長(zhǎng)時(shí)間的觀察和測(cè)量。吞吐量包括了分配內(nèi)存所花費(fèi)的時(shí)間在內(nèi)(一般來說無需對(duì)分配進(jìn)行調(diào)優(yōu))。暫停(Pause)指由于進(jìn)行垃圾收集而導(dǎo)致應(yīng)用無法響應(yīng)的時(shí)間。

    用戶對(duì)于垃圾收集有不同的需求,例如,對(duì)于Web服務(wù)器應(yīng)用來說,吞吐量是要著重考慮的,而暫停時(shí)間可能由于網(wǎng)絡(luò)的反應(yīng)時(shí)間而不那么明顯;而對(duì)于一個(gè)交互式圖形界面的應(yīng)用來說,即使是短暫的暫停都會(huì)帶來非常不好的用戶體驗(yàn)。

    通常來說,如何設(shè)置代的大小是在這些考慮因素之間作出的一個(gè)權(quán)衡。例如,將新生代設(shè)置得很大會(huì)得到很好的吞吐性能,但是會(huì)增加暫停時(shí)間;反之,較小的新生代設(shè)置會(huì)減小暫停時(shí)間,但是降低了吞吐量。一個(gè)代的大小不應(yīng)該影響在其他代上進(jìn)行垃圾收集的頻率和暫停時(shí)間。

    對(duì)于代的大小設(shè)置,沒有一個(gè)精確的計(jì)算方法。同時(shí)考慮應(yīng)用對(duì)內(nèi)存的使用特征以及用戶對(duì)垃圾收集的需求,才能夠做出最好的選擇。因此,虛擬機(jī)默認(rèn)的垃圾收集的相關(guān)參數(shù)可能不是最優(yōu)的,需要通過用戶定制這些命令行選項(xiàng)加以調(diào)整。

    2.2. 測(cè)量

    對(duì)于特定的應(yīng)用來說,吞吐量和內(nèi)存占用還是比較容易測(cè)量的。例如對(duì)于一個(gè)web服務(wù)應(yīng)用,可以使用壓力測(cè)試工具來測(cè)量它的吞吐量,內(nèi)存占用可以使用Solaris操作系統(tǒng)提供的命令pmap來測(cè)量。另外,通過打開虛擬機(jī)的詳細(xì)診斷信息來估算垃圾回收的暫停時(shí)間。

    通過使用虛擬機(jī)選項(xiàng)-verbose:gc,能夠?qū)⒚看问占瘯r(shí)的一些信息打印出來。需要注意的是,對(duì)于不同版本的J2SE平臺(tái)來說,-verbose:gc的輸出格式可能稍有差異。下面的示例是一個(gè)大型的服務(wù)器應(yīng)用的-verbose:gc輸出。

    [GC 325407K->83000K(776768K), 0.2300771 secs]

    [GC 325816K->83372K(776768K), 0.2454258 secs]

    [Full GC 267628K->83769K(776768K), 1.8479984 secs]

    上面的輸出中,表明虛擬機(jī)進(jìn)行了兩次次要收集和一次主要收集。箭頭兩端的數(shù)字

    325407K->83000K(第一行)

    表示在進(jìn)行垃圾收集之前和之后活動(dòng)對(duì)象的總大小。在次要收集之后的數(shù)字(83000K)包含了那些并不是必要活動(dòng)的對(duì)象,但是還不能被回收。因?yàn)檫@些對(duì)象可能本身是活動(dòng)的,或者有來自舊生代的引用。括弧中的數(shù)字

    (776768K)(第一行)

    表示總共的可用空間的大小。這個(gè)大小不包括持久代在內(nèi),是堆的大小減去一個(gè)存活空間的大小。此次次要收集大約用了1/4秒

    0.2300771 secs (第一行)

    主要收集的輸出格式和第三行相似。如果使用了-XX:+PrintGCDetail選項(xiàng),就會(huì)將垃圾收集時(shí)的詳細(xì)信息打印出來。同樣,對(duì)于不同的J2SE平臺(tái)版本,根據(jù)虛擬機(jī)的需要,-XX:+PrintGCDetail的輸出格式也有所不同。下面就是在J2SE平臺(tái)1.4.2版本上使用-XX:+PrintGCDetail參數(shù)的輸出示例:

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

    從上面的輸出信息可以看出,次要收集釋放了新生代大約98%的空間,

    DefNew: 64575K->959K(64576K)

    用了大約46毫秒,

    0.0457646 secs

    整個(gè)堆空間的使用率下降到51%左右

    196016K->133633K(261184K)

    最后看到,相對(duì)于新生代的收集,在時(shí)間消耗上稍微多了一點(diǎn)點(diǎn),

    0.0459067 secs

    選項(xiàng)-XX:+PrintGCTimeStamps在輸出垃圾收集信息的時(shí)候帶有時(shí)間戳。

    111.042: [GC 111.042: [DefNew: 8128K->8128K(8128K), 0.0000505 secs]111.042: [Tenured: 18154K->2311K(24576K), 0.1290354 secs] 26282K->2311K(32704K), 0.1293306 secs]

    收集在111秒的時(shí)候開始,幾乎同時(shí)次要收集也開始了。對(duì)于新生代上的主要收集也有了一些附加信息,新生代的使用率下降到10%

    18154K->2311K(24576K)

    用了大約0.13秒

    0.1293306 secs

    3. 調(diào)整代大小

    很多參數(shù)都能夠影響代的大小,下圖表示的就是約定空間(committed space)和虛擬空間(virtual space)之間的不同。在虛擬機(jī)初始化的時(shí)候,整個(gè)空間都為堆保留。可以通過-Xmx參數(shù)指定整個(gè)空間的大小,如果-Xms參數(shù)的值比-Xmx小,那么在一開始,堆所保留的空間可能到不了-Xmx參數(shù)指定的值,那么未保留的這部分空間就被表示為虛擬的。在需要更大的空間的時(shí)候,堆的不同部分(新生代,舊生代,持久代)都可能增長(zhǎng)直到其上限。

    有些參數(shù)指定的是堆中一部分空間和另外一部分的大小比率,例如,NewRatio參數(shù)表示舊生代和新生代的比率。稍后會(huì)有關(guān)于這些參數(shù)的討論。

    3.1. 堆的總體大小

    當(dāng)某個(gè)代被充滿的時(shí)候,就會(huì)發(fā)生垃圾收集,所以,吞吐量和可用內(nèi)存的大小成反比,總內(nèi)存大小是影響垃圾收集的最重要因素。

    默認(rèn)情況下,虛擬機(jī)總是試圖收縮內(nèi)存大小,來保證每個(gè)代內(nèi)的活動(dòng)對(duì)象所占用的空間的比率維持在特定范圍,這個(gè)范圍就是由參數(shù)-XX:MinHeapFreeRatio=<最小值>和-XX:MaxHeapFreeRatio=<最大值>以及-Xms和-Xmx來確定。在Solaris操作系統(tǒng)平臺(tái)(SPARC版本)如下表所示:

    -XX:MinHeapFreeRatio=

    40

    -XX:MaxHeapFreeRatio=

    70

    -Xms

    3670k

    -Xmx

    64m

    如果使用默認(rèn)值,那么在某個(gè)代中,當(dāng)空閑空間低于40%,那么虛擬機(jī)就會(huì)增長(zhǎng)這個(gè)空間以使得空閑空間能夠保持在40%以上,假設(shè)這個(gè)代的大小未超過最大限制。類似的,如果代中空閑空間的大小超過了70%,虛擬機(jī)就會(huì)收縮這個(gè)代的大小,使空閑比率降到70%以下,當(dāng)然了,要高于40%。

    根據(jù)經(jīng)驗(yàn),這些默認(rèn)的參數(shù)設(shè)置不適和大型的服務(wù)器應(yīng)用,一個(gè)問題就是啟動(dòng)緩慢,因?yàn)槎训某跏即笮”容^小,不得不進(jìn)行多次的主要收集來釋放空間,另外一個(gè)問題就是-Xmx參數(shù)的默認(rèn)設(shè)置對(duì)于這些服務(wù)器應(yīng)用來說是很不合理的,所以,對(duì)于服務(wù)器應(yīng)用,有這樣的指導(dǎo)規(guī)則:

    · 除非在垃圾收集的時(shí)候暫?,F(xiàn)象嚴(yán)重,否則要盡可能多的給虛擬機(jī)分配內(nèi)存,64M通常都太小了

    · 設(shè)置-Xms和-Xmx一樣大,以避免虛擬機(jī)在收縮大小時(shí)的消耗。另外,如果你做出了糟糕的選擇,虛擬機(jī)無法補(bǔ)償

    · 當(dāng)增加了處理器之后,要相應(yīng)的增加虛擬機(jī)內(nèi)存大小,因?yàn)閮?nèi)存分配是可以并行進(jìn)行的

    關(guān)于虛擬機(jī)的全部參數(shù)的解釋,可以參考:

    http://java.sun.com/docs/hotspot/VMOptions.html

    3.2. 新生代

    第二個(gè)重要的影響因素是虛擬機(jī)中新生代的大小。新生代越大,次要回收發(fā)生的次數(shù)就越少。當(dāng)然,對(duì)于一定大小的堆來說,新生代越大,就意味著舊生代越小,那么就會(huì)使得主要回收的次數(shù)增多。最佳選擇應(yīng)該參考應(yīng)用創(chuàng)建的對(duì)象的存活周期來設(shè)定。

    默認(rèn)情況下,新生代的大小是由NewRatio參數(shù)來設(shè)置的,例如設(shè)置-XX:NewRatio=3表示新生代和舊生代之間的比率為1:3,就是說Eden和存活空間總共占堆大小的1/4。

    參數(shù)NewSize和MaxNewSize指定了新生代大小的范圍,設(shè)定這個(gè)參數(shù)就意味著限定了新生代的大小,就像使用-Xms和-Xmx參數(shù)限制堆的大小一樣。最好將新生代的大小設(shè)定為經(jīng)過NewRatio參數(shù)計(jì)算出的大小的整倍數(shù)。

    3.3. 新生代的保證

    理想的次要收集會(huì)將活動(dòng)對(duì)象從新生代的一部分(Eden和第一個(gè)存活空間)復(fù)制到另外一部分(第二個(gè)存活空間)。但是,無法保證第二個(gè)存活空間能夠容納全部活動(dòng)對(duì)象。所以,在舊生代一定要有足夠的空閑空間來容納全部的活動(dòng)對(duì)象。最糟糕的情況就是在舊生代的空閑空間為Eden大小加上非空存活空間的大小。當(dāng)舊生代也沒有足夠的空閑空間的時(shí)候,就需要進(jìn)行一次主要收集。對(duì)于小型應(yīng)用來說,這種策略是可以滿足需要的,因?yàn)樵谂f生代的內(nèi)存主要是虛擬約定的,并未真正使用。但是對(duì)于需要很大堆內(nèi)存的服務(wù)器應(yīng)用來說,大于堆虛擬約定內(nèi)存一半的Eden大小是沒有任何意義的:只會(huì)發(fā)生主要收集。需要指出的是,在新生代能夠使用除"吞吐收集器"(throughput collector)之外的其他類型的收集器。如果舊生代無法容納新生代復(fù)制過來的活動(dòng)對(duì)象,吞吐收集器會(huì)在這個(gè)兩個(gè)代上都進(jìn)行垃圾收集。

    如果有特殊需要,使用參數(shù)SurvivorRatio可以調(diào)整存活空間的大小,但是通常這個(gè)參數(shù)對(duì)性能的影響不那么重要。例如,-XX:SurvivorRatio=6就設(shè)定了每個(gè)存活空間和Eden的比率為1 :6,換句話說,就是每個(gè)存活空間占新生代大小的1/8(不是1/7,因?yàn)橛袃蓚€(gè)存活空間)。

    如果存活空間設(shè)置的太小,就會(huì)導(dǎo)致過于頻繁的向舊生代復(fù)制對(duì)象;如果存活空間設(shè)置的太大,就會(huì)因?yàn)榭臻e而白白浪費(fèi)。虛擬機(jī)的垃圾收集器都會(huì)為對(duì)象在復(fù)制到舊生代之前的反轉(zhuǎn)復(fù)制次數(shù)選擇一個(gè)閥值,通過設(shè)定這個(gè)閥值來保證存活空間一直處于半滿狀態(tài)。通過指定-XX:+PrintTenuringDistribution參數(shù)可以觀察到這個(gè)閥值,以及新生代中對(duì)象的"年齡"。同時(shí),這個(gè)參數(shù)對(duì)于觀察應(yīng)用產(chǎn)生對(duì)象的存活期分布是很有幫助的。

    下面是Solaris操作系統(tǒng)平臺(tái)(SPARC版本)上一些參數(shù)的默認(rèn)值:

    NewRatio

    2(client虛擬機(jī)是8)

    NewSize

    2228k

    MaxNewSize

    無限

    SurvivorRatio

    32

    新生代的最大大小是根據(jù)堆的總大小以及NewRatio來計(jì)算出來的,默認(rèn)的"無限"表示:除非在命令行中指定了MaxNewSize,否則該計(jì)算出來的值不限制MaxNewSize的大小。

    對(duì)于服務(wù)器應(yīng)用,有這樣的指導(dǎo)規(guī)則:

    · 首先確定能夠給虛擬機(jī)使用的最大內(nèi)存,然后通過調(diào)整新生代的大小來找到滿足性能需求的最佳值

    · 除非發(fā)現(xiàn)性能瓶頸在于頻繁的主要收集或者暫停時(shí)間,盡可能多的給新生代分配內(nèi)存

    · 將新生代大小設(shè)置到接近堆大小的一半會(huì)適得其反

    · 當(dāng)增加了處理器之后,要相應(yīng)的增加新生代大小,因?yàn)閮?nèi)存分配是可以并行進(jìn)行的

    4. 收集器類型

    到目前為止,我們還只是針對(duì)默認(rèn)的垃圾收集器展開討論。從J2SE平臺(tái)1.4.2版本開始,加入了另外3種垃圾收集器,都是著重提高吞吐能力,降低垃圾收集時(shí)的暫停時(shí)間。

    1. 吞吐收集器(throughput collector):命令行參數(shù):-XX:+UseParallelGC。在新生代使用并行收集策略,在舊生代和默認(rèn)收集器相同。

    2. 并發(fā)收集器(concurrent low pause collector):命令行參數(shù):-XX:+UseConcMarkSweepGC。在舊生代使用并發(fā)收集策略,大部分收集工作都是和應(yīng)用并發(fā)進(jìn)行的,在進(jìn)行收集的時(shí)候,應(yīng)用的暫停時(shí)間很短。如果綜合使用-XX:+UseParNewGC和-XX:+UseConcMarkSweepGC,那么在新生代上使用并行的收集策略。

    3. 增量收集器(incremental low pause collector):命令行參數(shù):-Xincgc。使用增量收集器要謹(jǐn)慎,他只是在每次進(jìn)行次要收集的時(shí)候?qū)εf生代進(jìn)行一部分的收集,這樣就把主要收集所帶來的較長(zhǎng)時(shí)間的停頓分散到多次的次要收集。但是,考慮到總共的吞吐,可能比舊生代上默認(rèn)的收集還要慢。

    注意,-XX:+UseParallelGC和XX:+UseConcMarkSweepGC不能同時(shí)使用。對(duì)于J2SE1.4.2版本會(huì)檢查垃圾收集相關(guān)參數(shù)組合的合法性,但是對(duì)于之前的版本沒有這個(gè)檢查,可能會(huì)導(dǎo)致不可預(yù)知的錯(cuò)誤。

    在嘗試使用其他的收集器之前,建議先使用默認(rèn)的收集器,通過調(diào)整代的大小以及相關(guān)參數(shù)來看看哪些方面不能滿足需求,通過以上信息提供的參考,再?zèng)Q定選擇其他的收集器。

    4.1. 何時(shí)使用吞吐收集器

    當(dāng)你的應(yīng)用運(yùn)行在多個(gè)處理器的主機(jī)上時(shí),考慮使用吞吐收集器。因?yàn)槟J(rèn)的收集器是由一個(gè)線程來完成收集工作的,因此會(huì)給應(yīng)用增加串行執(zhí)行時(shí)間。吞吐收集器是多線程的進(jìn)行次要收集的,所以可以降低應(yīng)用的串行執(zhí)行時(shí)間。一種典型的情況就是應(yīng)用中有很多線程都在創(chuàng)建對(duì)象。這種情況下也需要增大新生代的大小。

    4.2. 吞吐收集器

    吞吐收集器和默認(rèn)的收集器類似,都是分代收集器。不同之處就在于吞吐收集器用多線程進(jìn)行次要收集,主要收集本質(zhì)上和默認(rèn)收集器相同。默認(rèn)情況下,在N個(gè)CPU的主機(jī)上,就會(huì)啟動(dòng)N個(gè)收集線程,收集線程的數(shù)量可以通過命令行選項(xiàng)進(jìn)行控制。在只有1顆CPU的主機(jī)上,吞吐收集器的性能表現(xiàn)可能還不如默認(rèn)收集器,因?yàn)橐恍┎⑿袌?zhí)行(例如進(jìn)行同步時(shí)的開銷)帶來了額外的開銷;在2顆CPU的主機(jī)上,吞吐收集器和默認(rèn)收集器性能相當(dāng);在多于2顆CPU的主機(jī)上,你會(huì)發(fā)現(xiàn)進(jìn)行次要收集的暫停時(shí)間降低了。

    通過命令行參數(shù)-XX:+UseParallelGC來指定使用吞吐收集器,ParallelGCThreads參數(shù)用來設(shè)置線程數(shù)量(-XX:ParallelGCThreads=<具體數(shù)值>)。吞吐收集器對(duì)堆內(nèi)存的需求和默認(rèn)收集器一樣。使用吞吐收集器能夠降低在新生代上進(jìn)行次要收集時(shí)的暫停時(shí)間,但是由于有多個(gè)線程參與次要收集,在從新生代向舊生代提升(promotion)的時(shí)候可能會(huì)產(chǎn)生碎片。為了進(jìn)行對(duì)象從新生代到舊生代的提升,每個(gè)垃圾收集線程都會(huì)保留一塊舊生代的空間,舊生代就被劃分成多個(gè)"提升緩沖"(promotion buffers),這樣就容易產(chǎn)生內(nèi)存碎片。減少收集線程的數(shù)量能夠減少碎片的產(chǎn)生,同時(shí)會(huì)增加舊生代的大小。

    4.2.1. 大小自適應(yīng)

    從J2SE平臺(tái)1.4.1版本開始,吞吐收集器就具有了一個(gè)特征,就是大小自適應(yīng)(參數(shù)-XX:+UseAdaptiveSizePolicy),這個(gè)選項(xiàng)默認(rèn)是打開的。該特征對(duì)于收集時(shí)間、分配比例、收集之后堆的空閑空間等數(shù)據(jù)進(jìn)行統(tǒng)計(jì)分析,然后以此為依據(jù)調(diào)整新生代和舊生代的大小以達(dá)到最佳效果??梢允褂?verbose:gc來查看堆的大小。

    4.2.2. Aggressive

    -XX:+AggressiveHeap選項(xiàng)會(huì)檢測(cè)主機(jī)的資源(內(nèi)存大小、處理器數(shù)量),然后調(diào)整相關(guān)的參數(shù),使得長(zhǎng)時(shí)間運(yùn)行的、內(nèi)存申請(qǐng)密集的任務(wù)能夠以最佳狀態(tài)運(yùn)行。該選項(xiàng)最初是為擁有大量?jī)?nèi)存和很多處理器的主機(jī)而設(shè)計(jì)的,但是從J2SE1.4.1以及其后繼版本來看,即使是對(duì)于那些只有4顆CPU的主機(jī),該選項(xiàng)都是很有幫助的。因此,吞吐收集器(-XX:+UseParallelGC)、大小自適應(yīng)(-XX:+UseAdaptiveSizePolicy)以及本選項(xiàng)(-XX:+AggressiveHeap)經(jīng)常結(jié)合在一起使用。要使用本選項(xiàng),主機(jī)上至少要有256M的物理內(nèi)存,堆內(nèi)存的最初大小是基于物理內(nèi)存計(jì)算出來的,然后會(huì)根據(jù)需要盡可能的利用物理內(nèi)存。

    4.2.3. 吞吐收集器的測(cè)量法

    -verbose:gc的使用和默認(rèn)收集器相同。

    4.3. 何時(shí)使用并發(fā)收集器

    如果你的應(yīng)用在運(yùn)行的時(shí)候能夠擁有足夠的處理器資源,并且減小垃圾收集的暫停時(shí)間能夠明顯提升應(yīng)用性能,此時(shí)考慮使用并發(fā)收集器。例如那些有大量相對(duì)長(zhǎng)生存期的對(duì)象(較大的舊生代)的應(yīng)用,并且運(yùn)行在有2顆甚至更多的CPU的主機(jī)上。但是實(shí)際上這種收集器是為那些需要短暫停時(shí)間的應(yīng)用所設(shè)計(jì)的。運(yùn)行在單處理器上的交互式應(yīng)用,如果設(shè)置一個(gè)合適的舊生代大小,能夠達(dá)到非常良好的效果。

    4.4. 并發(fā)收集器

    并發(fā)收集器和默認(rèn)收集器類似,都是分代收集器。并發(fā)收集器在舊生代上并發(fā)進(jìn)行垃圾收集。

    并發(fā)收集器旨在降低舊生代上進(jìn)行收集的暫停時(shí)間,他使用一組互相隔離的收集線程,每個(gè)線程負(fù)責(zé)一部分的主要收集,這個(gè)收集過程和應(yīng)用的運(yùn)行是并發(fā)進(jìn)行的。通過命令行選項(xiàng)-XX:+UseConcMarkSweepGC來使用并發(fā)收集器。每當(dāng)發(fā)生主要收集的時(shí)候,并發(fā)收集器在收集開始的時(shí)候和中期會(huì)短時(shí)間的暫停所有的應(yīng)用線程,中期的暫停時(shí)間相對(duì)長(zhǎng)一點(diǎn),在這次暫停中,多個(gè)線程同時(shí)工作完成收集任務(wù)。剩余的收集工作將由一個(gè)收集線程完成,這次是和應(yīng)用并發(fā)執(zhí)行的。次要收集的過程和默認(rèn)收集器類似,也可以使用多線程的方式完成次要收集,參看"并發(fā)收集器的并行次要收集"章節(jié)。

    在下面連接中對(duì)并發(fā)收集器(針對(duì)舊生代)中用到的技術(shù)進(jìn)行了詳細(xì)的闡述:

    http://research.sun.com/techrep/2000/abstract-88.html

    4.4.1. 并發(fā)的額外開銷

    雖然并發(fā)收集器有效的降低了收集時(shí)的暫停時(shí)間,但卻是以使用更多的處理器資源為代價(jià)的。收集過程中并發(fā)進(jìn)行的那一部分是由單一的一個(gè)線程完成的。對(duì)于一個(gè)在N個(gè)處理器上運(yùn)行的系統(tǒng),并發(fā)進(jìn)行的那部分會(huì)使用1/N的處理器資源。可能在單處理器的系統(tǒng)上你看到他表現(xiàn)也還可以,那只是偶然罷了。當(dāng)然,它能夠?qū)⒁淮伍L(zhǎng)時(shí)間的暫停(這里的暫停指所有的應(yīng)用線程都不可用了)分割成多個(gè)短時(shí)間的暫停,但是這個(gè)并不是它的設(shè)計(jì)初衷。同時(shí),并發(fā)收集會(huì)有額外的開銷,并且可能降低系統(tǒng)吞吐能力,同時(shí)對(duì)于某些類型的應(yīng)用來說,并發(fā)收集是有先天缺陷的(例如容易造成內(nèi)存碎片)。在擁有2顆處理器的系統(tǒng)上,并發(fā)收集在執(zhí)行的時(shí)候,還有1顆處理器可以為應(yīng)用服務(wù),因此,執(zhí)行收集不會(huì)"暫停"應(yīng)用的運(yùn)行。雖然降低了暫停時(shí)間,但是并發(fā)收集確實(shí)占用了一部分處理器資源,所以你可能感覺到應(yīng)用會(huì)有所緩慢。N的值越大,在并發(fā)收集上所用的處理器資源就越少,并發(fā)收集器的優(yōu)勢(shì)就越明顯。

    4.4.2. 新生代的保證

    如果使用默認(rèn)收集器,那么在進(jìn)行次要收集的時(shí)候,必須保證舊生代中有足夠的空間來容納從Eden和存活空間復(fù)制過去的對(duì)象。由于并發(fā)收集會(huì)產(chǎn)生內(nèi)存碎片,所以這個(gè)保證的條件就更加苛刻:在舊生代必須要有足夠的連續(xù)空間來容納來自Eden和一個(gè)存活空間的對(duì)象,因?yàn)闆]有什么方式能夠準(zhǔn)確知道Eden和這個(gè)存活空間中對(duì)象大小的分布情況(主要是為了避免巨大的性能消耗)。相對(duì)于默認(rèn)收集器,并發(fā)收集器往往需要更大的堆內(nèi)存。在默認(rèn)收集器時(shí),堆內(nèi)存需要保留但是不一定真正的使用。先使用默認(rèn)收集器,找到一個(gè)新生代和舊生代大小的合適的估算值,然后將舊生代的大小設(shè)置成和新生代一樣大再去使用并發(fā)收集器。這只是一個(gè)非常粗略的近似值,至于實(shí)際上的最佳設(shè)置是由應(yīng)用來決定的。

    4.4.3. 完全收集

    在舊生代被填滿之前,并發(fā)收集器使用一個(gè)收集線程來完成收集工作,同時(shí)不暫停應(yīng)用的執(zhí)行。實(shí)際上,即使應(yīng)用的線程都在運(yùn)行,收集器都可以并發(fā)來做更多的工作,所以,對(duì)于應(yīng)用而言,只會(huì)感覺到非常短暫的暫停。但是當(dāng)舊生代在填滿之前如果收集工作無法全部完成,那么就會(huì)暫停應(yīng)用的線程來完成所有的收集工作。這就是我們所說的完全收集(full collections)。如果發(fā)現(xiàn)完全收集比較頻繁,可能需要調(diào)整并發(fā)收集的相關(guān)參數(shù)。

    4.4.4. 漂浮垃圾

    垃圾收集的工作就是查找堆中的所有活動(dòng)對(duì)象。當(dāng)應(yīng)用的線程和垃圾收集的線程并發(fā)執(zhí)行的時(shí)候,那么對(duì)于收集線程來說當(dāng)時(shí)是活動(dòng)的對(duì)象可能在收集工作完成之后就變成了非活動(dòng)對(duì)象。這就是所說的"漂浮垃圾"(floating garbage)。漂浮垃圾的數(shù)量和并發(fā)收集的時(shí)間有關(guān)(應(yīng)用線程需要花一些時(shí)間才丟棄對(duì)象),和應(yīng)用的細(xì)節(jié)也有關(guān)系??梢酝ㄟ^增加舊生代20%(這個(gè)是估計(jì)值)解決漂浮垃圾問題。當(dāng)然了,在下一輪收集的時(shí)候,這些垃圾都將被收集掉。

    4.4.5. 暫停

    在一次并發(fā)收集周期,需要兩次暫停應(yīng)用。第一次暫停時(shí),標(biāo)識(shí)所有的可以從根對(duì)象(例如線程棧,靜態(tài)對(duì)象等)或者堆中的其它對(duì)象(例如新生代)直接到達(dá)的對(duì)象,這就是"初始標(biāo)識(shí)"(initial mark)。緊接著就是第二次暫停,此次暫停的目的是為了找出由于收集和應(yīng)用的并發(fā)執(zhí)行而疏漏的、未被標(biāo)識(shí)對(duì)象,這叫做"重新標(biāo)識(shí)"(remark)。

    4.4.6. 并發(fā)階段

    在初始標(biāo)識(shí)和重新標(biāo)識(shí)之間有一個(gè)并發(fā)標(biāo)識(shí)的過程,在并發(fā)標(biāo)識(shí)的時(shí)候,收集線程需要占用一部分本來屬于應(yīng)用的處理器資源。在重新標(biāo)識(shí)階段之后,還有一個(gè)并發(fā)清理過程,同樣,也會(huì)占用一部分處理器資源。在清理階段之后,并發(fā)收集線程進(jìn)入休眠狀態(tài),直到下一輪主要收集的發(fā)生。

    4.4.7. 并發(fā)收集的測(cè)量

    下面是使用了-XX:+PrintGCDetails參數(shù)的-verbose:gc輸出(已經(jīng)刪除了一些詳細(xì)信息),我們可以看到并發(fā)收集的輸出中穿插了很多次要收集,一般來說,一個(gè)并發(fā)收集周期中,會(huì)有多次的次要收集。CMS-initial-mark表示并發(fā)收集周期的開始,CMS-concurrent-mark表示并發(fā)標(biāo)識(shí)階段的結(jié)束,CMS-concurrent-sweep表示并發(fā)清理階段的結(jié)束。我們之前沒有討論的預(yù)清理階段(precleaning phase)由CMS-concurrent-preclean標(biāo)識(shí),它表示的是可以并發(fā)執(zhí)行的一些工作并且是為重新標(biāo)識(shí)階段(CMS-remark)做好了準(zhǔn)備。最后一個(gè)階段由CMS-concurrent-reset標(biāo)識(shí),表示已經(jīng)為下一輪的并發(fā)收集做好了準(zhǔn)備。

    [GC [1 CMS-initial-mark: 13991K(20288K)] 14103K(22400K), 0.0023781 secs]

    [GC [DefNew: 2112K->64K(2112K), 0.0837052 secs] 16103K->15476K(22400K), 0.0838519 secs]

    ...

    [GC [DefNew: 2077K->63K(2112K), 0.0126205 secs] 17552K->15855K(22400K), 0.0127482 secs]

    [CMS-concurrent-mark: 0.267/0.374 secs]

    [GC [DefNew: 2111K->64K(2112K), 0.0190851 secs] 17903K->16154K(22400K), 0.0191903 secs]

    [CMS-concurrent-preclean: 0.044/0.064 secs]

    [GC[1 CMS-remark: 16090K(20288K)] 17242K(22400K), 0.0210460 secs]

    [GC [DefNew: 2112K->63K(2112K), 0.0716116 secs] 18177K->17382K(22400K), 0.0718204 secs]

    [GC [DefNew: 2111K->63K(2112K), 0.0830392 secs] 19363K->18757K(22400K), 0.0832943 secs]

    ...

    [GC [DefNew: 2111K->0K(2112K), 0.0035190 secs] 17527K->15479K(22400K), 0.0036052 secs]

    [CMS-concurrent-sweep: 0.291/0.662 secs]

    [GC [DefNew: 2048K->0K(2112K), 0.0013347 secs] 17527K->15479K(27912K), 0.0014231 secs]

    [CMS-concurrent-reset: 0.016/0.016 secs]

    [GC [DefNew: 2048K->1K(2112K), 0.0013936 secs] 17527K->15479K(27912K), 0.0014814 secs]

    初始標(biāo)識(shí)的暫停相對(duì)于次要收集的暫停要短,反之,并發(fā)階段(并發(fā)標(biāo)識(shí),并發(fā)預(yù)清理,并發(fā)清理)的暫停可能相對(duì)要長(zhǎng)一些,但是在收集的過程中,應(yīng)用不會(huì)有任何暫停。而由于標(biāo)識(shí)所引起的暫停和應(yīng)用的細(xì)節(jié)(例如頻繁的修改對(duì)象會(huì)增加暫停時(shí)間)以及上一次次要收集的時(shí)間(例如新生代中有大量的對(duì)象時(shí)也會(huì)增加暫停時(shí)間)有關(guān)。

    4.4.8. 并發(fā)收集器的并行次要收集

    在多處理器平臺(tái)上,可以使用參數(shù)UseParNewGC來降低次要收集的暫停時(shí)間:

    -XX:+UseParNewGC

    如果使用了UseParNewGC,那么同時(shí)使用CMSParallelRemarkEnabled參數(shù)可以降低標(biāo)識(shí)暫停:

    -XX:+CMSParallelRemarkEnabled

    4.5. 何時(shí)使用增量收集器

    如果你的應(yīng)用可以用較頻繁的、較長(zhǎng)時(shí)間的新生代上收集來換取稍短時(shí)間的舊生代收集,就可以考慮使用增量收集器。典型情況是如果需要長(zhǎng)時(shí)間的舊生代收集時(shí)(大量的長(zhǎng)存活期對(duì)象),小型的新生代收集也能夠滿足(大部分對(duì)象是短存活期的),并且只有一個(gè)處理器。

    4.6. 增量收集器

    同樣,增量收集器也是和默認(rèn)收集器類似的分代收及器,在新生代上的次要收集和默認(rèn)收集器一樣。不要在使用增量收集器的同時(shí)使用-XX:+UseParallelGC或者-XX:+UseParNewGC。在舊生代上的主要收集是增量完成的。

    這種收集器在每次做次要收集的時(shí)候,進(jìn)行一部分的主要收集,這樣就避免了做完整的主要收集所帶來的長(zhǎng)時(shí)間暫停。但是有時(shí)候?yàn)榱吮苊獬霈F(xiàn)內(nèi)存溢出(out of memory)的問題,也會(huì)在舊生代上進(jìn)行完整的主要收集(就象默認(rèn)收集器那樣)。

    由于這種收集器會(huì)在堆內(nèi)存上產(chǎn)生碎片,所以相對(duì)于默認(rèn)的標(biāo)識(shí)-清理-壓縮(mark-sweep-compact)收集器來說,可能需要更大一些的堆內(nèi)存。

    為了能夠在每次次要收集時(shí)進(jìn)行一部分的主要收集,收集器需要維護(hù)一些附加信息,所以,增量收集的總體消耗要高一些,并且吞吐可能不如默認(rèn)收集器那么好。

    首先使用默認(rèn)收集器找到一個(gè)合適的堆大小,如果此時(shí)主要收集的暫停時(shí)間還是無法滿足應(yīng)用需求,嘗試調(diào)整各個(gè)代的大小,并且使用增量收集器,直到找到合適的堆設(shè)置。

    · 如果在使用增量收集器的時(shí)候發(fā)生了完全收集(full collection),可能在舊生代發(fā)生內(nèi)存溢出之前無法完成增量的垃圾收集,這個(gè)時(shí)候,你需要減小新生代的大小,以迫使次要收集發(fā)生頻率更高一些。

    · 如果由于無法滿足新生代保證而發(fā)生的主要收集,那么會(huì)產(chǎn)生內(nèi)存碎片。一次次要收集沒有能夠回收任何空間,此時(shí)表明無法保證新生代需求了,此時(shí)嘗試增大舊生代大小來彌補(bǔ)碎片問題,可能不會(huì)真正使用很大的舊生代,但是對(duì)于新生代保證來說是有幫助的。

    4.6.1. 增量收集器測(cè)量

    將-verbose:gc和-XX:+PrintGCDetail組合使用,可以看到如下的輸出:

    [GC [DefNew: 2074K->25K(2112K), 0.0050065 secs][Train: 1676K->1633K(63424K), 0.0082112 secs] 3750K->1659K(65536K), 0.0138017 secs]

    從上面的輸出可以看出,進(jìn)行次要收集用時(shí)大約5毫秒,同時(shí)還有一次增量收集(Train:…),用時(shí)大約8毫秒。如果發(fā)生了完全收集,在輸出中會(huì)看到Train:MSC字樣:

    [GC [DefNew: 2049K->2049K(2112K), 0.0003304 secs][Train MSC: 61809K->357K(63424K), 0.3956982 secs] 63859K->394K(65536K), 0.3987650 secs]

    同時(shí),從上面的輸出中可以看出,次要收集并沒有起到作用:收集前后都是2049K,這就表明了在舊生代上沒有連續(xù)的空間能夠滿足新生代保證。

    5. 其他考慮事項(xiàng)

    對(duì)于大部分應(yīng)用來說,持久代的大小不會(huì)影響垃圾收集的性能。但是有些應(yīng)用會(huì)動(dòng)態(tài)的產(chǎn)生或者加載大量的對(duì)象,例如JSP的容器,如果需要,可以使用參數(shù)ManPermSize來增加持久代的大小。

    有些應(yīng)用的finalization或者弱引用/軟引用/幻影引用(weak/soft/phantom refrences)和垃圾收集相互影響。這種特點(diǎn)可能從Java語言本身就造成了很差的垃圾收集性能,一個(gè)典型的例子就是依賴對(duì)象的finalize方法來釋放資源,比如關(guān)閉文件描述符(file descriptor),這樣就極大地影響了垃圾收集的性能。無論如何,依賴?yán)占瘉磲尫刨Y源都是非常不可取的方式。

    應(yīng)用影響垃圾收集器的另外一種方式就是顯式的調(diào)用垃圾回收,例如調(diào)用System.gc()方法。這個(gè)調(diào)用強(qiáng)制進(jìn)行主要收集,對(duì)于大型應(yīng)用的可擴(kuò)展性有很大的傷害。可以使用參數(shù)-XX:+DisableExplicitGC來禁止應(yīng)用顯式的調(diào)用垃圾收集。

    另外就是在RMI分布式垃圾收集(RMI distributed garbage collection, DGC)時(shí)經(jīng)常遇到使用顯式的垃圾收集,應(yīng)用通過使用RMI引用在另外一個(gè)Java虛擬機(jī)中的對(duì)象,在這種分布式應(yīng)用中,垃圾對(duì)象無法通過傳統(tǒng)的垃圾收集進(jìn)行清理,所以RMI強(qiáng)制進(jìn)行周期性的垃圾收集??梢酝ㄟ^一些屬性來設(shè)置收集周期:

    java -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 ...

    默認(rèn)的收集周期是1分鐘,上面的參數(shù)指定的周期為1小時(shí)。但是,這樣設(shè)置可能會(huì)使得某些對(duì)象要經(jīng)過很長(zhǎng)時(shí)間才能夠被回收。如果對(duì)于DGC沒有時(shí)間上的需求限制,可以設(shè)置為L(zhǎng)ong.MAX_VALUE。

    Solaris 8操作系統(tǒng)平臺(tái)使用另外一個(gè)版本的線程庫(libthread)能夠?qū)⒕€程綁定為輕量進(jìn)程(light-weight process, LWP),對(duì)于一些應(yīng)用來說可能這個(gè)版本的線程庫比較有益處。要使用這個(gè)線程庫,在啟動(dòng)Java虛擬機(jī)時(shí)在環(huán)境變量LD_LIBRARY_PATH中包含/usr/lib/lwp。在Solaris 9上,這個(gè)線程庫是默認(rèn)的。

    相對(duì)于客戶端模式的虛擬機(jī)(-client選項(xiàng)),當(dāng)使用服務(wù)器模式的虛擬機(jī)時(shí)(-server選項(xiàng)),對(duì)于軟引用(soft reference)的清理力度要稍微差一些??梢酝ㄟ^增大-XX:SoftRefLRUPolicyMSPerMB=1000來降低收集頻率。默認(rèn)值是1000,也就是說每秒一兆字節(jié)。

    6. 總結(jié)

    根據(jù)應(yīng)用的需求不同,垃圾收集可能會(huì)成為性能的瓶頸。如果充分了解應(yīng)用的需求,并且深入理解垃圾收集的機(jī)制以及相關(guān)選項(xiàng),能夠?qū)⒗占瘜?duì)性能的影響降至最小。

    7. 其他文檔

    7.1. 輸出示例

    GC輸出示例列出了不同類型的垃圾收集的行為,以及對(duì)于垃圾收集詳細(xì)信息的診斷,并描述了如何來分析問題。

    http://java.sun.com/docs/hotspot/gc1.4.2/example.html

    7.2. 常見問題

    對(duì)于常見問題的一些解答,比本文檔要詳細(xì)一些。

    http://java.sun.com/docs/hotspot/gc1.4.2/faq.html

    原文出處:http://java.sun.com/docs/hotspot/gc1.4.2/

    posted on 2008-04-14 00:21 YODA 閱讀(1779) 評(píng)論(0)  編輯  收藏

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 日本中文字幕免费看| 亚洲在成人网在线看| 香港经典a毛片免费观看看| 日韩欧美一区二区三区免费观看| 一区二区三区在线免费观看视频| 日本不卡在线观看免费v| 亚洲成a∧人片在线观看无码| 97无码免费人妻超级碰碰碰碰| 亚洲日本va在线观看| 成人啪精品视频免费网站| 亚洲va中文字幕| 亚洲 小说区 图片区 都市| www在线观看免费视频| 亚洲精品国产精品乱码不99 | 亚洲AV色吊丝无码| WWW亚洲色大成网络.COM| 四虎影视永久免费观看网址| 无码免费又爽又高潮喷水的视频 | 成人影片麻豆国产影片免费观看 | 国产婷婷高清在线观看免费| 看Aⅴ免费毛片手机播放| 1000部啪啪未满十八勿入免费| 亚洲国产综合在线| 日韩在线视频免费看| eeuss草民免费| 久久久久亚洲av无码专区导航| 在线看免费观看AV深夜影院| 亚洲AV日韩AV永久无码色欲| 亚洲成人免费电影| 色偷偷尼玛图亚洲综合| 亚洲精品无码久久久久去q| 免费AA片少妇人AA片直播 | 男女猛烈无遮掩视频免费软件| 亚洲熟妇中文字幕五十中出| **实干一级毛片aa免费| 亚洲AV无码XXX麻豆艾秋| 亚洲av无码潮喷在线观看| 国语成本人片免费av无码| 国产成人1024精品免费| 亚洲国产最大av| 亚洲精品字幕在线观看|