java垃圾回收機(jī)制_第1頁
java垃圾回收機(jī)制_第2頁
java垃圾回收機(jī)制_第3頁
全文預(yù)覽已結(jié)束

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、上次講到引用類型和基本類型由于內(nèi)存分配上的差異導(dǎo)致的性能問題。那么今天就來聊一下和內(nèi)存釋放(主要是 gc)有關(guān)的話題。事先聲明一下:雖說 sun 公司已經(jīng)被 oracle 吞并了,但是出于習(xí)慣,同時(shí)也為了偷懶節(jié)省打字,以下仍然稱之為 sun 公司。jvm 的內(nèi)存在 java 虛擬機(jī)規(guī)范中(具體章節(jié)請(qǐng)看“這里”),提及了如下幾種類型的內(nèi)存空間:棧內(nèi)存(stack):每個(gè)線程私有的。堆內(nèi)存(heap):所有線程公用的。方法區(qū)(methodarea):有點(diǎn)像以前常說的“進(jìn)程代碼段”,這里面存放了每個(gè)加載類的反射信息、類函數(shù)的代碼、編譯時(shí)常量等信息。原生方法棧(nativemethodstack):主

2、要用于 jni 中的原生代碼,平時(shí)很少涉及。關(guān)于棧內(nèi)存(stack)和堆內(nèi)存(heap),已經(jīng)在上次的帖子中掃盲過了,大伙兒應(yīng)該有點(diǎn)印象。由于今天咱們要討論的“垃圾回收”話題,主要是和堆內(nèi)存(heap)有關(guān)。其它的幾個(gè)玩意兒不是今天討論的重點(diǎn)。等以后有空了,或許可以單獨(dú)聊一下。垃圾回收機(jī)制簡(jiǎn)介其實(shí) java 虛擬機(jī)規(guī)范中并未規(guī)定垃圾回收的相關(guān)細(xì)節(jié)。垃圾回收具體該怎么搞,完全取決于各個(gè) jvm 的設(shè)計(jì)者。所以,不同的 jvm 之間,gc 的行為可能會(huì)有一定的差異。下面咱拿 sun 官方的 jvm 來簡(jiǎn)單介紹一下 gc 的機(jī)制。啥時(shí)候進(jìn)行垃圾回收?一般情況下,當(dāng) jvm 發(fā)現(xiàn)堆內(nèi)存比較緊張、不太夠

3、用時(shí),它就會(huì)著手進(jìn)行垃圾回收工作。但是大伙兒要認(rèn)清這樣一個(gè)殘酷的事實(shí):jvm 進(jìn)彳 fgc 的時(shí)間點(diǎn)是無法準(zhǔn)確預(yù)知的。因?yàn)?gc 啟動(dòng)的時(shí)刻會(huì)受到各種運(yùn)行環(huán)境因素的影響,隨機(jī)性太大。雖說咱們無法準(zhǔn)確預(yù)知,但如果你想知道每次垃圾回收?qǐng)?zhí)行的情況,還是蠻方便的。可以通過 jvm 的命令行參數(shù)“-xx:+printgc”把相關(guān)信息打印出來。另外,調(diào)用 system.gc()R 是建議 jvm 進(jìn)彳 fgc。至于 jvm 到底會(huì)不會(huì)做,那就不好說啦。通常不建議自己手動(dòng)調(diào)用 system.gc(),還是讓 jvm 自行決定比較好。另外,使用 jvm 命令行參數(shù)-xx:+disableexplicitgc可

4、以讓 system.gc(pp 起作用。誰來負(fù)責(zé)垃圾回收?一般情況下,jvm 會(huì)有一個(gè)或多個(gè)專門的垃圾回收線程,由它們負(fù)責(zé)清理回收垃圾內(nèi)存。如何發(fā)現(xiàn)垃圾對(duì)象?垃圾回收線程會(huì)從“根集(rootset)”開始進(jìn)行對(duì)象引用的遍歷。所謂的“根集”,就是正在運(yùn)行的線程中,可以訪問的引用變量的集合(比如所有線程當(dāng)前函數(shù)的參數(shù)和局部變量、當(dāng)前類的成員變量等等)。垃圾回收線程先找出被根集直接引用的所有對(duì)象(不妨叫集合 1),然后再找出被集合 1 直接引用的所有對(duì)象(不妨叫集合 2),然后再找出被集合 2 直接引用的所有對(duì)象如此循環(huán)往復(fù),直到把能遍歷到的對(duì)象都遍歷完。凡是從根集通過上述遍歷可以到達(dá)的對(duì)象,都稱為

5、可達(dá)對(duì)象或有效對(duì)象;反之,則是不可達(dá)對(duì)象或失效對(duì)象(也就是垃圾)。如何清理/回收垃圾?通過上述階段,就把垃圾對(duì)象都找出來。然后垃圾回收線程會(huì)進(jìn)行相應(yīng)的清理和回收工作,包括:把垃圾內(nèi)存重新變?yōu)榭捎脙?nèi)存、進(jìn)行內(nèi)存的整理以消除內(nèi)存碎片、等等。這個(gè)過程會(huì)涉及到若干算法,有興趣的同學(xué)可以參見“這里限于篇幅,咱就不深入聊了。分代早期的 jvm 是不采用分代技術(shù)的,所有被 gc 管理的對(duì)象都存放在同一個(gè)堆里面。這么做的缺點(diǎn)比較明顯:每次進(jìn)行 gc 都要遍歷所有對(duì)象,開銷很大。其實(shí)大部分的對(duì)象生命周期都很短(短命對(duì)象),只有少數(shù)對(duì)象比較長(zhǎng)壽;在這些短命對(duì)象中,又只有少數(shù)對(duì)象占用的內(nèi)存空間大;其它大量的短命對(duì)象

6、都屬于小對(duì)象(很符合二八原理)。有鑒于此,從 jdk1.2 之后,jvm 開始使用分代的垃圾回收(generationalgarbagecollection)ojvm 把 gc 相關(guān)的內(nèi)存分為年老代(tenured)和年輕代(nursery)、持久彳 t(permanent,對(duì)應(yīng)于 jvm 規(guī)范的方法區(qū))。大部分對(duì)象在剛創(chuàng)建時(shí),都位于年輕代。如果某對(duì)象經(jīng)歷了幾輪 gc 還活著(大齡對(duì)象),就把它移到年老代。另外,如果某個(gè)對(duì)象在創(chuàng)建時(shí)比較大,可能就直接被丟到年老代。經(jīng)過這種策略,使得年輕代總是保存那些短命的小對(duì)象。在空間尺寸上,年輕代相對(duì)較小,而年老代相對(duì)較大。因?yàn)橛辛朔执夹g(shù),jvm 的 gc

7、 也相應(yīng)分為兩種:主要收集(majorcollection)和次要收集(minorcollection)o主要收集同時(shí)清理年老代和年輕代,因此開銷很大,不常進(jìn)行;次要收集僅僅清理年輕代,開銷很小,經(jīng)常進(jìn)行。gc 對(duì)性能會(huì)有啥影響?剛才介紹了 gc 的大致原理,那 gc 對(duì)性能會(huì)造成哪些影響捏?主要有如下幾個(gè)方面:造成當(dāng)前運(yùn)行線程的停頓早期的 gc 比較弱智。在它工作期間,所有其它的線程都被暫停(以免影響垃圾回收工作)。等到 gc 干完活,其它線程再繼續(xù)運(yùn)行。所以,早期 jdk 的gc 一旦開始工作,整個(gè)程序就會(huì)陷入假死狀態(tài),失去各種響應(yīng)。經(jīng)過這些年的技術(shù)改進(jìn)(包括采用分代技術(shù)), 從 jdk1

8、.4 開始, gc 已經(jīng)比較精明了。 在它干活期間, 只是偶爾暫停一下其它線程的運(yùn)行(從長(zhǎng)時(shí)間假死變?yōu)闀簳r(shí)性休克)。遍歷對(duì)象引用的開銷試想如果 jvm 中的對(duì)象很多,那遍歷完所有可達(dá)對(duì)象肯定是比較費(fèi)勁的工作,這個(gè)開銷可不小。清理和回收垃圾的開銷遍歷完對(duì)象引用之后,對(duì)垃圾的清理和回收也有較大的開銷。這部分開銷可能包括復(fù)制內(nèi)存塊、更新對(duì)象引用等等。幾種收集器兩個(gè)性能指標(biāo)因?yàn)榻裉炝牡氖切阅艿脑掝},必然會(huì)提到衡量 gc 性能的兩個(gè)重要指標(biāo):吞吐量(throughput)和停頓時(shí)間(pausetime)。吞吐量這個(gè)詞不是很直觀,解釋一下:就是 jvm 不用于 gc 的時(shí)間占總時(shí)間的比率。吞吐量是越大越好

9、,停頓時(shí)間是越小越好。不同的應(yīng)用程序?qū)@兩個(gè)指標(biāo)的關(guān)注點(diǎn)不一樣(后面具體會(huì)說),也就是所謂的“眾口難調(diào)”。很多 jvm 廠商為了迎合“眾口”,不得不提供多種幾種垃圾收集器供使用者選擇。不同的收集器,采用的收集策略是不一樣的,下面具體介紹。串行收集器(serialcollector)使用命令彳 f 選項(xiàng)-xx:+useserialgc”指定。這種收集器是最傳統(tǒng)的收集器。它使用單線程進(jìn)行垃圾回收,對(duì)于單 cpu 機(jī)器比較合適。另外,小型應(yīng)用或者對(duì)上述兩個(gè)指標(biāo)沒有特殊要求的,可以使用串行收集器。并行收集器(parallelthroughputcollector)顧名思義,這種收集器使用多個(gè)線程進(jìn)行垃

10、圾回收以達(dá)到高吞吐量。垃圾回收線程的數(shù)量通過命令行選項(xiàng)-xx:parallelgcthreads=n”指定??梢栽O(shè)置該數(shù)值以便充分利用多 cpu/多核。當(dāng)使用命令行選項(xiàng)-xx:+useparallelgc”時(shí):它會(huì)針對(duì)年輕代使用多個(gè)垃圾回收線程,對(duì)年老代依然使用單個(gè)線程的串行方式。此選項(xiàng)最早在 jdk1.5 引入。當(dāng)使用命令行選項(xiàng)-xx:+useparalleloldgc時(shí):它針對(duì)年輕代和年老代都使用多個(gè)垃圾回收線程的方式。不過此選項(xiàng)從 jdk1.6 才開始引入。并發(fā)收集器(concurrentlowpausecollector)使用命令彳 f 選項(xiàng)“-xx:+useconcmarksweep

11、gc指定。這種收集器優(yōu)先保證程序的響應(yīng)。它會(huì)盡量讓垃圾回收線程和應(yīng)用自身的線程同時(shí)運(yùn)行,從而降低停頓時(shí)間。此選項(xiàng)從 jdk1.4.1 開始支持。增量收集器(incrementalcollector)自從 jdk1.4.2 以來,sun 官方就停止維護(hù)該收集器了。所以俺就節(jié)省點(diǎn)口水,不多說了。如何降低 gc 的影響?盡量減少堆內(nèi)存的使用由于 gc 是針對(duì)存儲(chǔ)在堆內(nèi)存的對(duì)象進(jìn)行的。咱們?nèi)绻诔绦蛑袦p少引用對(duì)象的分配(也就相應(yīng)降低堆內(nèi)存分配),那對(duì)于提高 gc 的性能是很有幫助滴。上次“字符串過濾實(shí)戰(zhàn)”的帖子給出了一個(gè)例子,示范了如何通過降低堆內(nèi)存的分配次數(shù)來提升性能。設(shè)置合適的堆內(nèi)存大小jvm 的

12、堆內(nèi)存是有講究的,不能太大也不能太小。如果堆內(nèi)存太小,jvm 老是感覺內(nèi)存不夠用,可能會(huì)導(dǎo)致頻繁進(jìn)行垃圾回收,影響了性能;如果堆內(nèi)存太大,以至于操作系統(tǒng)的大部分物理內(nèi)存都被 jvm 自個(gè)兒霸占了,那可能會(huì)影響其它應(yīng)用程序甚至操作系統(tǒng)本身的性能。另外,年輕代的大小(或者說年輕代與年老代的比值)對(duì)于 gc 的性能也有明顯影響。如果年輕代太小,可能導(dǎo)致次要收集很頻繁;如果年輕代太大,導(dǎo)致次要收集的停頓很明顯。jvm 提供了若干和堆內(nèi)存大小相關(guān)的命令行選項(xiàng),具體如下:-xms 設(shè)置初始堆內(nèi)存-xmx 設(shè)置最大堆內(nèi)存-xmn 設(shè)置年輕代的大小-xx:newratio=n 設(shè)置年輕代與年老代的比例為n-xx:newsize=n 設(shè)置年輕代大小為n一般情況下,jvm 的默認(rèn)參數(shù)值已經(jīng)夠用。所以沒事兒別輕易動(dòng)用上述選項(xiàng)。如果你非調(diào)整不可,一定要做深入的性能對(duì)比測(cè)試,保證調(diào)整后的

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論