久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

成為JavaGC專家Part I — 深入淺出Java垃圾回收機(jī)制

 goldbomb 2013-03-05

英文原文:cubrid,編譯:ImportNew- 王曉杰

對于Java開發(fā)人員來說,,了解垃圾回收機(jī)制(GC)有哪些好處呢,?首先可以滿足作為一名軟件工程師的求知欲,其次,,深入了解GC如何工作可以幫你寫出更好的Java應(yīng)用,。

這僅僅代表我個(gè)人的意見,但我堅(jiān)信一個(gè)精通GC的人往往是一個(gè)好的Java開發(fā)者,。如果你對GC的處理過程感興趣,,說明你已經(jīng)具備較大規(guī)模應(yīng)用的開發(fā)經(jīng)驗(yàn)。如果你曾經(jīng)想過如何正確的選擇GC算法,,那意味著你已經(jīng)完全理解你所開發(fā)的應(yīng)用的特點(diǎn),。當(dāng)然,我們不能以偏概全,,這不能作為評價(jià)一個(gè)好的開發(fā)人員的共通標(biāo)準(zhǔn),。但是,我要說的是,,深入理解GC是成為一名偉大的程序員的必經(jīng)之路。

這是成為JavaGC專家系列文章的第一篇,,本篇主要針對GC機(jī)制進(jìn)行介紹,,在下一篇中,我們將重點(diǎn)探討分析GC狀態(tài)以及來自NHN的GC調(diào)優(yōu)的例子。

本文的目的是以一種簡單的方式向你介紹GC機(jī)制。我希望這些文章能夠幫到你,。實(shí)際上,,我的學(xué)生已經(jīng)在Twitter上發(fā)布了一些很好的關(guān)于Java內(nèi)核的文章,并且大受歡迎,。有興趣的話,你也可以關(guān)注他們。

回到正題,,咱們繼續(xù)談垃圾回收,在學(xué)習(xí)GC之前,,你首先應(yīng)該記住一個(gè)單詞:“stop-the-world”,。Stop-the-world會在任何一種GC算法中發(fā)生。Stop-the-world意味著 JVM 因?yàn)橐獔?zhí)行GC而停止了應(yīng)用程序的執(zhí)行,。當(dāng)Stop-the-world發(fā)生時(shí),,除了GC所需的線程以外,所有線程都處于等待狀態(tài),,直到GC任務(wù)完成,。GC優(yōu)化很多時(shí)候就是指減少Stop-the-world發(fā)生的時(shí)間。

按代的垃圾回收機(jī)制

在Java程序中不能顯式地分配和注銷內(nèi)存,。有些人把相關(guān)的對象設(shè)置為null或者調(diào)用System.gc()來試圖顯式地清理內(nèi)存,。設(shè)置為null至少沒什么壞處,但是調(diào)用System.gc()會顯著地影響系統(tǒng)性能,,必須徹底杜絕(還好,,我還沒有見到NHN的哪個(gè)開發(fā)者調(diào)用這個(gè)方法)。

在Java中,,開發(fā)人員無法直接在程序代碼中清理內(nèi)存,,而是由垃圾回收器自動尋找不必要的垃圾對象,并且清理掉他們,。垃圾回收器會在下面兩種假設(shè)(hypotheses)成立的情況下被創(chuàng)建(稱之為假設(shè)不如改為推測(suppositions)或者前提(preconditions)),。

  • 大多數(shù)對象會很快變得不可達(dá)

  • 只有很少的由老對象(創(chuàng)建時(shí)間較長的對象)指向新生對象的引用

這些假設(shè)我們稱之為弱年代假設(shè)weak generational hypothesis)。為了強(qiáng)化這一假設(shè),,HotSpot虛擬機(jī)將其物理上劃分為兩個(gè)–新生代(young generation)和老年代(old generation),。
新生代(Young generation): 絕大多數(shù)最新被創(chuàng)建的對象會被分配到這里,,由于大部分對象在創(chuàng)建后會很快變得不可到達(dá),所以很多對象被創(chuàng)建在新生代,,然后消失,。對象從這個(gè)區(qū)域消失的過程我們稱之為”minor GC“。

老年代(Old generation): 對象沒有變得不可達(dá),,并且從新生代中存活下來,,會被拷貝到這里。其所占用的空間要比新生代多,。也正由于其相對較大的空間,發(fā)生在老年代上的GC要比新生代少得多,。對象從老年代中消失的過程,,我們稱之為”major GC“(或者”full GC“)

請看下面這個(gè)圖表,。

 圖1 : GC 空間 & 數(shù)據(jù)流

上圖中的持久代( permanent generation )也被稱為方法區(qū)method area),。他用來保存類常量以及字符串常量,。因此,,這個(gè)區(qū)域不是用來永久的存儲那些從老年代存活下來的對象,。這個(gè)區(qū)域也可能發(fā)生GC。并且發(fā)生在這個(gè)區(qū)域上的GC事件也會被算為major GC,。

有些人可能會問:
如果老年代的對象需要引用一個(gè)新生代的對象,,會發(fā)生什么呢?
為了解決這個(gè)問題,,老年代中存在一個(gè)”card table“,,他是一個(gè)512 byte大小的塊。所有老年代的對象指向新生代對象的引用都會被記錄在這個(gè)表中,。當(dāng)針對新生代執(zhí)行GC的時(shí)候,只需要查詢card table來決定是否可以被收集,,而不用查詢整個(gè)老年代,。這個(gè)card table由一個(gè)write barrier來管理。write barrier給GC帶來了很大的性能提升,,雖然由此可能帶來一些開銷,,但GC的整體時(shí)間被顯著的減少。

圖 2: Card Table 結(jié)構(gòu)

 新生代的構(gòu)成

為了更好地理解GC,,我們現(xiàn)在來學(xué)習(xí)新生代,,新生代是用來保存那些第一次被創(chuàng)建的對象,,他可以被分為三個(gè)空間

  •  一個(gè)伊甸園空間(Eden

  •  兩個(gè)幸存者空間(Survivor

一共有三個(gè)空間,其中包含兩個(gè)幸存者空間,。每個(gè)空間的執(zhí)行順序如下:

  1. 絕大多數(shù)剛剛被創(chuàng)建的對象會存放在伊甸園空間,。

  2. 在伊甸園空間執(zhí)行了第一次GC之后,存活的對象被移動到其中一個(gè)幸存者空間,。

  3.   此后,在伊甸園空間執(zhí)行GC之后,,存活的對象會被堆積在同一個(gè)幸存者空間,。

  4.  當(dāng)一個(gè)幸存者空間飽和,還在存活的對象會被移動到另一個(gè)幸存者空間,。之后會清空已經(jīng)飽和的那個(gè)幸存者空間,。

  5. 在以上的步驟中重復(fù)幾次依然存活的對象,就會被移動到老年代,。

如果你仔細(xì)觀察這些步驟就會發(fā)現(xiàn),,其中一個(gè)幸存者空間必須保持是空的。如果兩個(gè)幸存者空間都有數(shù)據(jù),,或者兩個(gè)空間都是空的,,那一定標(biāo)志著你的系統(tǒng)出現(xiàn)了某種錯誤。
通過頻繁的minor GC將數(shù)據(jù)移動到老年代的過程可以用下圖來描述:

圖 3: GC執(zhí)行前后對比

需要注意的是HotSpot虛擬機(jī)使用了兩種技術(shù)來加快內(nèi)存分配,。他們分別是是”bump-the-pointer“和“TLABs(Thread-Local Allocation Buffers)”,。

Bump-the-pointer技術(shù)跟蹤在伊甸園空間創(chuàng)建的最后一個(gè)對象。這個(gè)對象會被放在伊甸園空間的頂部,。如果之后再需要創(chuàng)建對象,,只需要檢查伊甸園空間是否有足夠的剩余空間。如果有足夠的空間,,對象就會被創(chuàng)建在伊甸園空間,,并且被放置在頂部。這樣以來,,每次創(chuàng)建新的對象時(shí),,只需要檢查最后被創(chuàng)建的對象。這將極大地加快內(nèi)存分配速度,。但是,,如果我們在多線程的情況下,事情將截然不同,。如果想要以線程安全的方式以多線程在伊甸園空間存儲對象,,不可避免的需要加鎖,而這將極大地的影響性能,。TLABs 是HotSpot虛擬機(jī)針對這一問題的解決方案,。該方案為每一個(gè)線程在伊甸園空間分配一塊獨(dú)享的空間,,這樣每個(gè)線程只訪問他們自己的TLAB空間,再與bump-the-pointer技術(shù)結(jié)合可以在不加鎖的情況下分配內(nèi)存,。
以上是針對新生代空間GC技術(shù)的簡要介紹,,你不需要刻意記住我剛剛提到的兩種技術(shù)。不知道他們不會對你產(chǎn)生什么影響,,但是請務(wù)必記住在對象剛剛被創(chuàng)建之后,,是保存在伊甸園空間的。那些長期存活的對象會經(jīng)由幸存者空間轉(zhuǎn)存在老年代空間,。

老年代GC處理機(jī)制

老年代空間的GC事件基本上是在空間已滿時(shí)發(fā)生,,執(zhí)行的過程根據(jù)GC類型不同而不同,因此,,了解不同的GC類型將有助于你理解本節(jié)的內(nèi)容,。
JDK7一共有5種GC類型:

  1. Serial GC

  2. Parallel GC

  3. Parallel Old GC (Parallel Compacting GC)

  4. Concurrent Mark & Sweep GC  (or “CMS”)

  5. Garbage First (G1) GC

其中,Serial GC不應(yīng)該被用在服務(wù)器上,。這種GC類型在單核CPU的桌面電腦時(shí)代就存在了,。使用Serial GC會顯著的降低應(yīng)用的性能指標(biāo)。
現(xiàn)在,,讓我們共同學(xué)習(xí)每一種GC類型

1. Serial GC (-XX:+UseSerialGC)

新生代空間的GC方式我們在前面已經(jīng)介紹過了,,在老年代空間中的GC采取稱之為”mark-sweep-compact“的算法。

  1. 算法的第一步是標(biāo)記老年代中依然存活對象,。(標(biāo)記)

  2. 第二步,,從頭開始檢查堆內(nèi)存空間,并且只留下依然幸存的對象,。(清理)

最后一步,,從頭開始,順序地填滿堆內(nèi)存空間,,并且將對內(nèi)存空間分成兩部分:一個(gè)保存著對象,,另一個(gè)空著(壓縮)。

2. Parallel GC (-XX:+UseParallelGC)

圖 4: Serial GC 與 Parallel GC的區(qū)別

從上圖中,,你可以輕易地看出serial GC和parallel GC的區(qū)別,,serial GC只使用一個(gè)線程執(zhí)行GC,而parallel GC使用多個(gè)線程,,因此parallel GC更高效,。這種GC在內(nèi)存充足以及多核的情況下會很有用,因此我們也稱之為”throughput GC“,。

3. Parallel Old GC(-XX:+UseParallelOldGC)

Parallel Old GC在JDK5之后出現(xiàn),。與parallel GC相比,唯一的區(qū)別在于針對老年代的GC算法。Parallel Old GC分為三步:標(biāo)記-匯總-壓縮(mark – summary – compaction),。匯總(summary)步驟與清理(sweep)的不同之處在于,,其將依然幸存的對象分發(fā)到GC預(yù)先處理好的不同區(qū)域,算法相對清理來說略微復(fù)雜一點(diǎn),。

4. CMS GC (-XX:+UseConcMarkSweepGC)

圖 5: Serial GC & CMS GC

就像你從上圖看到的那樣, CMS GC比我之前解釋的各種算法都要復(fù)雜很多,。第一步初始化標(biāo)記(initial mark) 比較簡單。這一步驟只是查找那些距離類加載器最近的幸存對象,。因此,,停頓的時(shí)間非常短暫。在之后的并行標(biāo)記( concurrent mark )步驟,,所有被幸存對象引用的對象會被確認(rèn)是否已經(jīng)被追蹤和校驗(yàn),。這一步的不同之處在于,在標(biāo)記的過程中,,其他的線程依然在執(zhí)行,。在重新標(biāo)記(remark)步驟,,會再次檢查那些在并行標(biāo)記步驟中增加或者刪除的與幸存對象引用的對象,。最后,在并行交換( concurrent sweep )步驟,,轉(zhuǎn)交垃圾回收過程處理,。垃圾回收工作會在其他線程的執(zhí)行過程中展開。一旦采取了這種GC類型,,由GC導(dǎo)致的暫停時(shí)間會極其短暫,。CMS GC也被稱為低延遲GC。它經(jīng)常被用在那些對于響應(yīng)時(shí)間要求十分苛刻的應(yīng)用之上,。

當(dāng)然,,這種GC類型在擁有stop-the-world時(shí)間很短的優(yōu)點(diǎn)的同時(shí),也有如下缺點(diǎn):

  •  它會比其他GC類型占用更多的內(nèi)存和CPU

  •  默認(rèn)情況下不支持壓縮步驟

在使用這個(gè)GC類型之前你需要慎重考慮,。如果因?yàn)閮?nèi)存碎片過多而導(dǎo)致壓縮任務(wù)不得不執(zhí)行,,那么stop-the-world的時(shí)間要比其他任何GC類型都長,你需要考慮壓縮任務(wù)的發(fā)生頻率以及執(zhí)行時(shí)間,。

5. G1 GC

最后,,我們來學(xué)習(xí)垃圾回收優(yōu)先(G1)GC類型。

圖 6:  G1 GC的結(jié)構(gòu)

 如果你想要理解G1,,首先你要忘記你所學(xué)過的新生代和老年代的概念,。正如你在上圖所看到的,每個(gè)對象被分配到不同的格子,,隨后GC執(zhí)行,。當(dāng)一個(gè)區(qū)域裝滿之后,對象被分配到另一個(gè)區(qū)域,并執(zhí)行GC,。這中間不再有從新生代移動到老年代的三個(gè)步驟,。這個(gè)類型是為了替代CMS GC而被創(chuàng)建的,因?yàn)镃MS GC在長時(shí)間持續(xù)運(yùn)作時(shí)會產(chǎn)生很多問題,。

G1最大的好處是性能,,他比我們在上面討論過的任何一種GC都要快。但是在JDK 6中,,他還只是一個(gè)早期試用版本,。在JDK7之后才由官方正式發(fā)布。就我個(gè)人看來,,NHN在將JDK 7正式投入商用之前需要很長的一段測試期(至少一年),。因此你可能需要再等一段時(shí)間。并且,,我也聽過幾次使用了JDK 6中的G1而導(dǎo)致Java虛擬機(jī)宕機(jī)的事件,。請耐心的等到它更穩(wěn)定吧。

下一次我將討論GC優(yōu)化相關(guān)的問題,,但是在此之前我要先明確一件事情,,假如應(yīng)用中創(chuàng)建的所有對象的大小和類型都是統(tǒng)一的,那么公司使用的WAS的GC參數(shù)可以是相同的,。但是WAS所創(chuàng)建對象的大小和生命周期根據(jù)服務(wù)以及硬件的不同而不同,。換句話說,不能因?yàn)槟硞€(gè)應(yīng)用使用的GC參數(shù)“A”,,就說明同樣的參數(shù)也能給其他服務(wù)帶來最佳的效果,。而是要因地制宜,有的放矢,。我們需要找到適合每個(gè)WAS線程的參數(shù),,并且持續(xù)的監(jiān)控和優(yōu)化每個(gè)設(shè)備上的WAS實(shí)例。這并不是我的一家之談,,而是負(fù)責(zé)Oracle Java虛擬機(jī)研發(fā)的工程師在 JavaOne 2010上已經(jīng)討論過的,。

本文中我們簡略的介紹了Java的GC機(jī)制,請繼續(xù)關(guān)于我們的后續(xù)文章,,我們將會討論如何監(jiān)控Java GC狀態(tài)以及優(yōu)化GC,。

另外,我特別推薦一本2011年12月發(fā)布的《Java性能》(Amazon,也可以通過safari在線閱讀),,還有在Oracle官網(wǎng)發(fā)布的白皮書《Java HotSpotTM虛擬機(jī)內(nèi)存管理》(這本書與Java性能優(yōu)化不是同一本) 作者Sangmin Lee, NHN公司,,性能工程師實(shí)驗(yàn)室高級工程師。

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多