Java性能调优:充分利用垃圾收集器
JVM背后發(fā)生了什么,垃圾回收如何影響Java性能?
性能調(diào)優(yōu)世界是一個(gè)危險(xiǎn)的地方,一個(gè)JVM標(biāo)志失衡,事情很快就會(huì)變得繁瑣。 因此 ,我們決定求助于Java性能調(diào)優(yōu)專家, 單調(diào) JVM探查器mjprof的創(chuàng)建者Haim Yadid 。 在這篇文章中,我們將分享他在實(shí)踐中經(jīng)受住考驗(yàn)的一些見(jiàn)解,并了解JVM內(nèi)部在壓力下的表現(xiàn)。
新帖:Java性能調(diào)優(yōu)–如何充分利用垃圾收集器http://t.co/NnzQpuWBHz pic.twitter.com/8zqMrUfSHl
— Takipi(@takipid) 2015年4月2日
了解您要面對(duì)的問(wèn)題
JVM受到垃圾收集暫停的影響,該暫停的頻率和持續(xù)時(shí)間各不相同。 在暫停過(guò)程中,一切都停止了,各種意外行為開(kāi)始發(fā)揮作用。 當(dāng)面對(duì)一個(gè)新的調(diào)優(yōu)項(xiàng)目時(shí),通常會(huì)發(fā)生以下兩種情況之一:公司已經(jīng)知道它存在垃圾回收問(wèn)題,或者很快就會(huì)發(fā)現(xiàn)它有一個(gè)問(wèn)題。 在此階段,他們很可能會(huì)遇到暫停,JVM卡住的不穩(wěn)定行為以及性能普遍下降。 這些癥狀通常是通過(guò)響應(yīng)時(shí)間慢,CPU和內(nèi)存利用率高或系統(tǒng)在大多數(shù)情況下正常運(yùn)行而具有不規(guī)則行為(例如,極其緩慢的事務(wù)和斷開(kāi)連接)而可見(jiàn)的。
主要陷阱:忽略異常值
可以通過(guò)一種常見(jiàn)的錯(cuò)誤來(lái)忽略這種行為,并且不會(huì)向任何人發(fā)出警報(bào),這是一個(gè)常見(jiàn)的錯(cuò)誤:測(cè)量平均交易時(shí)間,并忽略異常值。 這就是GC問(wèn)題隱藏的地方:盡管大多數(shù)情況下系統(tǒng)可能表現(xiàn)正常,但有時(shí)系統(tǒng)的響應(yīng)能力卻會(huì)下降,并給許多用戶帶來(lái)不良的體驗(yàn)。 例如,一個(gè)通常需要100毫秒的事務(wù)會(huì)受到GC暫停的影響,并突然花費(fèi)幾秒鐘甚至一分鐘。 在電子商務(wù)站點(diǎn)中,如果系統(tǒng)的維護(hù)人員僅查看平均交易時(shí)間,則除用戶以外的任何人都不會(huì)注意到。 另一個(gè)容易被忽視的問(wèn)題是,當(dāng)系統(tǒng)吞吐量受到影響時(shí)(例如命中率達(dá)到20%),并且它無(wú)法充分發(fā)揮其潛力。 您可能永遠(yuǎn)不會(huì)知道出了什么問(wèn)題,因?yàn)槟鷽](méi)有查看正確的指標(biāo)。 很多時(shí)候,原因是對(duì)GC開(kāi)銷的了解不足,并且只關(guān)注平均響應(yīng)時(shí)間的一個(gè)指標(biāo),而忽略了第99個(gè)百分位數(shù)。
定義性能要求:頻率和持續(xù)時(shí)間
這里的主要問(wèn)題是:您認(rèn)為應(yīng)用程序中GC暫停頻率和持續(xù)時(shí)間的可接受標(biāo)準(zhǔn)是什么? 例如,每天暫停15秒可能是可以接受的,而30分鐘一次的頻率對(duì)產(chǎn)品來(lái)說(shuō)絕對(duì)是災(zāi)難。 這些要求來(lái)自每個(gè)系統(tǒng)的領(lǐng)域,在這些領(lǐng)域中,實(shí)時(shí)和高頻交易系統(tǒng)將具有最嚴(yán)格的要求。
總體而言,看到15到17秒的停頓并不罕見(jiàn)。 某些系統(tǒng)甚至可能達(dá)到40-50秒的暫停,Haim也有機(jī)會(huì)在具有大量批處理工作的大堆的系統(tǒng)中看到5分鐘的暫停。 因此,暫停持續(xù)時(shí)間在這里并不重要。
停止世界收集數(shù)據(jù):GC日志的重要性
在基于HotSpot JVM的系統(tǒng)中,垃圾收集狀態(tài)最豐富的數(shù)據(jù)源是GC日志。 如果您的JVM沒(méi)有生成帶有時(shí)間戳的GC日志,那么您就錯(cuò)過(guò)了用于分析和解決暫停問(wèn)題的重要數(shù)據(jù)源。 這對(duì)于開(kāi)發(fā)環(huán)境,登臺(tái),負(fù)載測(cè)試以及最重要的是在生產(chǎn)中都是如此。 您可以獲取有關(guān)系統(tǒng)中所有GC事件的數(shù)據(jù),無(wú)論這些事件是同時(shí)完成的還是引起世界停頓的:這些事件花費(fèi)了多長(zhǎng)時(shí)間,消耗了多少CPU以及釋放了多少內(nèi)存。 從這些數(shù)據(jù)中,您可以了解這些暫停的頻率和持續(xù)時(shí)間,它們的開(kāi)銷,然后繼續(xù)采取行動(dòng)以減少它們。
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:mygclogfilename.gc GC日志數(shù)據(jù)收集的最小設(shè)置
從指標(biāo)來(lái)看,5%通常是可接受的GC開(kāi)銷的上限,而一個(gè)應(yīng)用程序與另一個(gè)應(yīng)用程序之間可接受的暫停時(shí)間卻大不相同。
這里值得提及的兩個(gè)用于GC日志分析的工具是Github上可用的開(kāi)源GC Viewer和jClarity的Censum 。
解決方案策略
獲得所需信息后,就可以檢查可能的原因和解決方案了。 您進(jìn)行的每項(xiàng)更改都要求進(jìn)行一次新測(cè)試,并進(jìn)行一輪日志收集,以評(píng)估其有效性并確定它是否有助于我們前進(jìn)并達(dá)到要求。 優(yōu)選在生產(chǎn)中和在壓力下。 我們可以通過(guò)4種主要方法來(lái)解決由GC暫停引起的問(wèn)題:切換垃圾收集器,調(diào)整控制Java堆的標(biāo)志,更改代碼以及使用其他JVM /收集器。 以下是對(duì)HotSpot領(lǐng)域中考慮的方法及其解決的問(wèn)題類型的快速概述:
1.錯(cuò)誤的垃圾收集器正在運(yùn)行
粗略地說(shuō),JVM有4個(gè)垃圾收集器,您可以選擇在啟動(dòng)期間使用哪個(gè)垃圾收集器。 要了解有關(guān)每種類型的更多信息,可以在此處查看比較。 GC問(wèn)題的一個(gè)常見(jiàn)原因是針對(duì)您正在開(kāi)發(fā)的應(yīng)用程序類型使用了錯(cuò)誤的收集器。 HotSpot的默認(rèn)值是并行/吞吐量收集器,通常它不是您的應(yīng)用程序的最佳選擇。 選擇正確的收集器的行為(通過(guò)JVM標(biāo)志)是對(duì)系統(tǒng)優(yōu)先級(jí)的聲明,通常是要考慮的第一個(gè)問(wèn)題。 通常,大多數(shù)并發(fā)的CMS和G1收集器將導(dǎo)致較少的暫停時(shí)間。 盡管出現(xiàn)暫停時(shí),其持續(xù)時(shí)間可能會(huì)比Parallel收集器引起的持續(xù)時(shí)間長(zhǎng),因?yàn)槠浠赝藱C(jī)制是單線程的(Ouch)。 另一方面,對(duì)于相同大小的堆,并行收集器將實(shí)現(xiàn)更高的吞吐量。 另一個(gè)準(zhǔn)則與可預(yù)測(cè)性有關(guān),如果可預(yù)測(cè)的性能是一個(gè)重要因素并且堆大小不大,那么并行收集器可能就是答案。 而且,如果平均響應(yīng)時(shí)間/延遲是您的重中之重,則CMS或G1最有可能是答案。
2.調(diào)優(yōu)Java堆
選擇了首選的GC算法之后,該進(jìn)行一些調(diào)整了。 測(cè)量(通過(guò)GC日志)吞吐量和暫停時(shí)間分布,如果您對(duì)此感到滿意,那就完成了。 如果GC開(kāi)銷很高(并且吞吐量很低),通常增加堆大小將改善這種情況。 當(dāng)要解決CMS或G1的長(zhǎng)時(shí)間停頓時(shí),情況就更加棘手。 造成碎片化的另一個(gè)原因是,JVM無(wú)法跟上對(duì)象從新一代遷移到舊一代的速度,然后需要暫停應(yīng)用程序?qū)ζ溥M(jìn)行修復(fù)。 解決方案是更早啟動(dòng)GC或增加堆大小。
從經(jīng)驗(yàn)來(lái)看,堆大小通常在1GB到8GB之間,而更大的堆則更為罕見(jiàn)。 在精簡(jiǎn)過(guò)程中,通常會(huì)在調(diào)整過(guò)程中將堆大小增加到8GB以上。 較大的堆大小的一個(gè)可行原因是,當(dāng)我們想要?jiǎng)?chuàng)建一個(gè)大的緩存時(shí),但這也可以在堆外解決。
讓我們來(lái)看另一個(gè)示例,以說(shuō)明需要調(diào)整溢出率的位置。 假設(shè)應(yīng)用程序需要100MB的空間來(lái)處理某些請(qǐng)求,而新一代的大小為50MB。 不應(yīng)該出現(xiàn)在舊一代中的對(duì)象將很快到達(dá)那里。 調(diào)整新世代和幸存者空間將需要解決這個(gè)問(wèn)題,并確保短暫生命的物體將在新世代中終結(jié)它們的生命。 影響這里的主要因素是堆大小,新舊發(fā)電比,幸存者空間大小以及最大使用期限閾值–一個(gè)對(duì)象移動(dòng)到舊發(fā)電需要多少GC周期。
我們需要考慮的另一個(gè)重要因素是應(yīng)用程序的“實(shí)時(shí)設(shè)置”。 意味著長(zhǎng)時(shí)間保留在內(nèi)存中的對(duì)象的大小,例如,活動(dòng)集的示例將是一個(gè)應(yīng)用緩存,其中包含頻繁的數(shù)據(jù)庫(kù)查詢結(jié)果集。 在調(diào)整JVM時(shí),需要確保“ liveset”可以方便地容納在舊版本中,并且除了消耗之外,該區(qū)域還具有足夠的可用內(nèi)存。 否則,將嚴(yán)重破壞JVM的行為,從而導(dǎo)致低吞吐量和頻繁的暫停。
3.架構(gòu)和代碼更改
一些問(wèn)題將迫使我們?cè)V諸代碼,甚至可能進(jìn)行體系結(jié)構(gòu)更改。 我們可以在此處解決的麻煩原因之一就是碎片化。 CMS收集器的長(zhǎng)時(shí)間停頓可能是由舊一代的碎片導(dǎo)致的。 每個(gè)GC周期都會(huì)釋放舊一代的內(nèi)存塊,使其看起來(lái)像瑞士奶酪,直到JVM 不能處理的時(shí)刻到來(lái)。 當(dāng)JVM將來(lái)自新一代的對(duì)象移動(dòng)到比這些“漏洞”更大的對(duì)象上,然后必須停止應(yīng)用程序來(lái)解決問(wèn)題時(shí),就會(huì)發(fā)生這種情況。 狀態(tài)隨時(shí)間變化的應(yīng)用程序必然會(huì)導(dǎo)致碎片化。 隨著狀態(tài)隨著時(shí)間的推移而變化,“舊狀態(tài)”對(duì)象將從舊版本中釋放,而它們的替換狀態(tài)在新一代中創(chuàng)建。 當(dāng)它最終晉升為老一代時(shí),它可能會(huì)不適用于正確的地方,這將導(dǎo)致碎片化。
對(duì)這類問(wèn)題的體系結(jié)構(gòu)解決方案可能是將對(duì)象更新到位,將“狀態(tài)”移到堆外機(jī)制或拆分進(jìn)程,對(duì)延遲敏感的關(guān)鍵路徑,其中有許多短期分配的對(duì)象到一個(gè)進(jìn)程,將大狀態(tài)移到另一個(gè)進(jìn)程一。
4.替代的JVM和垃圾收集器
如果暫停時(shí)間對(duì)您的應(yīng)用程序至關(guān)重要,并且Hotspot JVM無(wú)法提供可接受的響應(yīng)時(shí)間,則還有兩個(gè)可能的選擇。 第一個(gè)是具有不間斷C4垃圾收集器的Azul Zing JVM 。 為了開(kāi)始使用Zing,您將需要具有相對(duì)較大的計(jì)算機(jī),并且堆大小必須從32GB開(kāi)始。 另一個(gè)尚不成熟的選擇,但如果您想生活在邊緣,可能值得一試。這是Shenandoah GC算法。 它使用了一種稱為布魯克轉(zhuǎn)發(fā)指針的技術(shù),該技術(shù)導(dǎo)致超低的暫停時(shí)間和合理的開(kāi)銷。
進(jìn)一步閱讀:領(lǐng)先的GC專家
為了更深入地了解Garbage Collection和JVM的內(nèi)部,以下是在GC領(lǐng)域中一些最有趣的人:
- 查理·亨特 ( Charlie Hunt )是Oracle Java平臺(tái)小組的成員,也是Java Performance一書(shū)的主要作者。
- C4不間斷垃圾收集器的創(chuàng)建者Azul Systems的首席技術(shù)官兼聯(lián)合創(chuàng)始人Gil Tene 。
- 性能調(diào)整和jClarity首席技術(shù)官兼聯(lián)合創(chuàng)始人Kirk Pepperdine 。
- Monica Beckwitt ,Java / JVM性能顧問(wèn)。
- Twitter的JVM / GC工程師Tony Printezis ,Oracle的前G1技術(shù)負(fù)責(zé)人。
- Oracle的JVM開(kāi)發(fā)人員Jon Masamitsu 。
- Christine H. Flood和Roman Kennke ,Shenandoah GC算法的開(kāi)發(fā)人員。
結(jié)論
垃圾回收是JVM中最引人入勝的主題之一,我們希望本文能幫助您更好地了解各個(gè)運(yùn)動(dòng)部件。 非常感謝Haim Yadid同意與我們分享他的經(jīng)驗(yàn)! 如果您有任何疑問(wèn)或想要澄清,請(qǐng)?jiān)谙旅娴脑u(píng)論部分中告訴我們。
翻譯自: https://www.javacodegeeks.com/2015/04/java-performance-tuning-getting-the-most-out-of-your-garbage-collector.html
總結(jié)
以上是生活随笔為你收集整理的Java性能调优:充分利用垃圾收集器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: linux菜单栏删除怎么恢复(linux
- 下一篇: 深圳开泥头车还要备案证吗(深圳开泥头车要