如何優(yōu)化 Java 性能谦屑?

對(duì)于 Java 性能比較關(guān)心的同學(xué)大概都知道《Java Performance》這本書(shū)吧慢,一般而言涛漂,很多同學(xué)在日常寫(xiě) Java Code 的時(shí)候很少去關(guān)心性能問(wèn)題,但是在我們寫(xiě) Code 的過(guò)程中必須考慮到性能對(duì)程序的影響检诗。小到我們使用位運(yùn)算來(lái)實(shí)現(xiàn)算術(shù)運(yùn)算匈仗,大到我們對(duì) Java 代碼的總體架構(gòu)設(shè)計(jì),「性能」其實(shí)離我們很近逢慌。本篇文章主要提到幾個(gè)點(diǎn)悠轩,希望能夠?qū)Υ蠹矣兴鶈l(fā)。

Java 性能優(yōu)化
Java 性能優(yōu)化

對(duì)于性能調(diào)優(yōu)而言攻泼,通常我們需要經(jīng)過(guò)以下三個(gè)步驟:1火架,性能監(jiān)控;2忙菠,性能剖析何鸡;3,性能調(diào)優(yōu)

作為國(guó)內(nèi)在技術(shù)層面遙遙領(lǐng)先的 APM 廠商牛欢,One APM 的 Ai 產(chǎn)品對(duì)于 Java Application 性能優(yōu)化提供了非常完善的指標(biāo):

Java 性能優(yōu)化
Java 性能優(yōu)化

性能監(jiān)控:
影響 Java 性能多維度指標(biāo)監(jiān)控

Java 性能優(yōu)化
Java 性能優(yōu)化

性能剖析:
Application 性能剖析

Java 性能優(yōu)化
Java 性能優(yōu)化

性能調(diào)優(yōu):通過(guò)分析影響Application性能問(wèn)題根源骡男,進(jìn)行優(yōu)化Application;

我們對(duì)于操作系統(tǒng)的性能關(guān)注主要在下面幾個(gè)點(diǎn)上:CPU 利用率傍睹、CPU 調(diào)度執(zhí)行隊(duì)列隔盛、內(nèi)存利用率犹菱、網(wǎng)絡(luò) I/O、磁盤(pán)I/O吮炕。

1.CPU 利用率

對(duì)于一個(gè)應(yīng)用來(lái)說(shuō)腊脱,為了讓?xiě)?yīng)用達(dá)到最好的性能和可擴(kuò)展性,我們不僅僅要充分利用 CPU 周期內(nèi)可用的部分龙亲,而且要讓這部分 CPU 的使用更有價(jià)值陕凹,而不是浪費(fèi)。能夠讓 CPU 的周期利用的更充分對(duì)于多線程應(yīng)用運(yùn)行在多處理器和多核系統(tǒng)上至很有挑戰(zhàn)性的俱笛。另外捆姜,當(dāng) CPU 達(dá)到飽和狀態(tài)的時(shí)候并不能說(shuō)明 CPU 的性能和伸縮性已經(jīng)達(dá)到了最佳的狀態(tài)。

為了區(qū)分應(yīng)用是如何利用 CPU 資源的迎膜,我們必須從操作系統(tǒng)級(jí)別來(lái)檢測(cè)泥技。在很多操作系統(tǒng)上,CPU 的利用率統(tǒng)計(jì)報(bào)告通常包括用戶和系統(tǒng)或內(nèi)核對(duì)操作系統(tǒng)的使用磕仅。用戶對(duì) CPU 的使用是指應(yīng)用用來(lái)執(zhí)行應(yīng)用代碼執(zhí)行所需要的時(shí)間珊豹。相比之下,內(nèi)核和系統(tǒng)對(duì) CPU 的使用是指應(yīng)用用來(lái)執(zhí)行操作系統(tǒng)內(nèi)核代碼鎖花費(fèi)的時(shí)間榕订。高的內(nèi)核或者系統(tǒng) CPU 使用率可以表明共享資源緊迫店茶,或者是有大量的 I/O 設(shè)備交互。理想的狀態(tài)為了提高應(yīng)用的性能和伸縮性劫恒,讓內(nèi)核或系統(tǒng) CPU 時(shí)間為 0%贩幻,因?yàn)榛ㄔ趫?zhí)行內(nèi)核或系統(tǒng)代碼的時(shí)間是可以用來(lái)執(zhí)行應(yīng)用代碼的。因此 CPU 使用優(yōu)化的一個(gè)正確方向就是盡可能減少 CPU 花在執(zhí)行內(nèi)核代碼或者系統(tǒng)代碼上的時(shí)間两嘴。

對(duì)于計(jì)算密集型應(yīng)用丛楚,性能監(jiān)控比監(jiān)測(cè)用戶 CPU 使用和內(nèi)核或系統(tǒng) CPU 使用要更深層次,在計(jì)算密集型應(yīng)用中憔辫,我們需要監(jiān)測(cè) CPU 時(shí)鐘周期內(nèi)的執(zhí)行執(zhí)行條數(shù)(Instructions per clock趣些;IPC),或者是每條 CPU 執(zhí)行所使用的CPU周期(cycles per instruction贰您;CPI)坏平。對(duì)于計(jì)算密集型應(yīng)用來(lái)說(shuō)我們從這兩個(gè)維度來(lái)監(jiān)測(cè) CPU 是不錯(cuò)的選擇,因?yàn)楝F(xiàn)代操作系統(tǒng)的打包 CPU 性能報(bào)告工具通常只會(huì)打印 CPU 的利用率锦亦,而不會(huì)打印 CPU 周期內(nèi) CPU 用來(lái)執(zhí)行指令的時(shí)間舶替。這意味著當(dāng) CPU 正在等待內(nèi)存中的數(shù)據(jù)的時(shí)候,操作系統(tǒng)CPU性能報(bào)告工具也會(huì)認(rèn)為 CPU 是正在使用的狀態(tài)杠园,我們把這個(gè)場(chǎng)景叫做「Stall」坎穿,這種場(chǎng)景經(jīng)常會(huì)發(fā)生,比如在 CPU 正在執(zhí)行指令的任何時(shí)候返劲,只要是指令需要的數(shù)據(jù)沒(méi)有準(zhǔn)備好玲昧,也就是沒(méi)有在寄存器或者CPU緩存內(nèi),都會(huì)發(fā)生「Stall」場(chǎng)景篮绿。

當(dāng)「Stall」場(chǎng)景發(fā)生的時(shí)候 CPU 會(huì)浪費(fèi)時(shí)鐘周期孵延,因?yàn)?CPU 必須要等待指令需要的數(shù)據(jù)到達(dá)寄存器或者緩沖器。而且在這個(gè)場(chǎng)景中亲配,數(shù)百個(gè) CPU 時(shí)鐘周期被浪費(fèi)是很正常的事情尘应,因此在計(jì)算密集型應(yīng)用中,提高性能的策略是減少「Stall」場(chǎng)景的發(fā)生或者是增強(qiáng) CPU 的緩存使用從而使得更少的 CPU 周期因?yàn)榈却龜?shù)據(jù)而浪費(fèi)掉吼虎。這類(lèi)的性能監(jiān)控知識(shí)已經(jīng)超越了本書(shū)的內(nèi)容犬钢,需要性能專(zhuān)家的幫助了。然而思灰,后面講到的 Oracle Solaris Studio Performance Analyzer 這種性能剖析工具將會(huì)包括此類(lèi)數(shù)據(jù)玷犹。

2.CPU 調(diào)度隊(duì)列

除了對(duì) CPU 使用的監(jiān)控,我們也可以通過(guò)監(jiān)控 CPU 執(zhí)行隊(duì)列來(lái)檢查系統(tǒng)是否已經(jīng)滿負(fù)載洒疚。執(zhí)行隊(duì)列是用來(lái)存儲(chǔ)輕量級(jí)進(jìn)程歹颓,這些進(jìn)程通常是已經(jīng)準(zhǔn)備好執(zhí)行了但是正在等待 CPU 調(diào)度而在調(diào)度隊(duì)列等待的一種狀態(tài),當(dāng)輕量級(jí)進(jìn)程別當(dāng)前處理器能來(lái)得及處理的數(shù)量更多的時(shí)候油湖,調(diào)度隊(duì)列將會(huì)產(chǎn)生巍扛。比較深的 CPU 調(diào)度隊(duì)列表明系統(tǒng)已經(jīng)滿負(fù)荷了。系統(tǒng)的執(zhí)行隊(duì)列深度等于虛擬處理器執(zhí)行不了的等待數(shù)乏德,虛擬處理器數(shù)等于系統(tǒng)的硬件線程數(shù)撤奸。我們可以用 JAVA 的 API 來(lái)拿到虛擬處理器數(shù)。

Runtime.avaliableProcessors()喊括。當(dāng)執(zhí)行隊(duì)列深度大于虛擬處理器個(gè)數(shù)的四倍或更多的時(shí)候胧瓜,操作系統(tǒng)將會(huì)出現(xiàn)反應(yīng)遲鈍的現(xiàn)象。

對(duì)于 CPU 調(diào)度隊(duì)列的檢測(cè)的一個(gè)通用指導(dǎo)是當(dāng)我們發(fā)現(xiàn)隊(duì)列深度高于虛擬進(jìn)程數(shù)一倍的時(shí)候就要注意了瘾晃,但是沒(méi)有必要立即采取行動(dòng)贷痪。當(dāng)大于三倍或四倍或者更高的時(shí)候就要注意了,解決問(wèn)題刻不容緩蹦误。

通常有兩個(gè)可選的途徑來(lái)觀察隊(duì)列的深度劫拢,第一個(gè)是通過(guò)增加 CPU 來(lái)分擔(dān)負(fù)載或者減少對(duì)現(xiàn)有 CPU 的負(fù)載。這種途徑從本質(zhì)上減少了每個(gè)執(zhí)行單元的負(fù)載線程數(shù)强胰,從而減少執(zhí)行執(zhí)行隊(duì)列的深度舱沧。

另外的一種途徑是通過(guò)剖析系統(tǒng)運(yùn)行的應(yīng)用來(lái)增加 CPU 的使用率,換個(gè)說(shuō)法就是尋找一種可以減少花費(fèi)在垃圾回收上的 CPU 周期偶洋,或者尋找更好的算法來(lái)以更少的 CPU 周期來(lái)執(zhí)行 CPU 指令熟吏。性能專(zhuān)家通常專(zhuān)注后面的一種途徑:減少代碼的執(zhí)行路徑長(zhǎng)度和更好的 CPU 指令選擇。Java 程序員可以通過(guò)更好的執(zhí)行算法和數(shù)據(jù)結(jié)構(gòu)來(lái)提高代碼的執(zhí)行效率。

3.內(nèi)存利用率

其實(shí)牵寺,除了 CPU 的使用率悍引,系統(tǒng)的內(nèi)存屬性也需要被監(jiān)控,這些屬性包括比如:分頁(yè)帽氓、交換趣斤、鎖、多線程引起的上下文交換等黎休。

交換通常發(fā)生在當(dāng)應(yīng)用需要的內(nèi)存大于實(shí)際的物理內(nèi)存的時(shí)候浓领,處理這種情況操作系統(tǒng)通常會(huì)配置一個(gè)相應(yīng)的區(qū)域叫做交換區(qū)。交換區(qū)通常位于物理磁盤(pán)上势腮,當(dāng)物理內(nèi)存內(nèi)應(yīng)用耗盡的時(shí)候联贩,操作系統(tǒng)會(huì)將一部分內(nèi)存數(shù)據(jù)暫時(shí)交換到磁盤(pán)空間上,這部分內(nèi)存區(qū)域通常是訪問(wèn)頻率最低的一塊區(qū)域捎拯,而不會(huì)影響比較「忙」的內(nèi)存區(qū)域泪幌;當(dāng)被交換到磁盤(pán)區(qū)域的內(nèi)存又被應(yīng)用訪問(wèn)的時(shí)候,這個(gè)時(shí)候就需要從磁盤(pán)交換區(qū)將以頁(yè)為單位讀入內(nèi)存玄渗,交換會(huì)影響應(yīng)用的性能座菠。

虛擬機(jī)的垃圾收集器在交換的時(shí)候性能非常差,因?yàn)槔占魉L問(wèn)的大部分區(qū)域都是不可達(dá)的藤树,也就是垃圾收集器會(huì)引起交換活動(dòng)的發(fā)生浴滴。場(chǎng)景是戲劇性的,如果垃圾收集的堆區(qū)域已經(jīng)被交換到了磁盤(pán)空間岁钓,這個(gè)時(shí)候?qū)?huì)以頁(yè)為單位發(fā)生交換升略,這樣才能夠被垃圾收集器所掃描到,在交換的過(guò)程中會(huì)戲劇性的引發(fā)垃圾收集器的收集時(shí)間延長(zhǎng)屡限,這個(gè)時(shí)候如果垃圾收集器是
「Stop The World」(使得應(yīng)用響應(yīng)停止)的品嚣,那么這個(gè)時(shí)間就會(huì)被延長(zhǎng)。

4.網(wǎng)絡(luò) I/O

分布式 Java 應(yīng)用的性能和伸縮性會(huì)受到網(wǎng)絡(luò)帶寬和網(wǎng)絡(luò)性能的限制钧大。例如翰撑,如果我們往網(wǎng)絡(luò)接口發(fā)送比他能夠處理的更多的數(shù)據(jù)包,數(shù)據(jù)包將會(huì)堆積在操作系統(tǒng)的緩沖區(qū)內(nèi)啊央,這將會(huì)引發(fā)應(yīng)用延遲眶诈,另外其他的情況也會(huì)導(dǎo)致網(wǎng)絡(luò)應(yīng)用的延遲。

區(qū)分和監(jiān)控的工具通常在操作系統(tǒng)的打包工具中很難找到瓜饥。盡管 Linux 提供了 Netstat 命令逝撬,Linux 和 Solaris 都提供了網(wǎng)絡(luò)使用情況的實(shí)現(xiàn),他們都提供了包括每秒發(fā)包乓土、接包宪潮、錯(cuò)包溯警、沖突等信息的統(tǒng)計(jì)。在以太網(wǎng)中狡相,一小部分包沖突是很正常的現(xiàn)象梯轻。如果錯(cuò)包情況比較多那可能是網(wǎng)卡有問(wèn)題了。同時(shí)谣光,盡管 netstat 可以統(tǒng)計(jì)網(wǎng)絡(luò)接口的發(fā)送和接收數(shù)據(jù)情況檩淋,這很難斷定網(wǎng)卡是否被充分利用。例如萄金,如果 Netstat -i 顯示現(xiàn)在每秒有 2500 個(gè)包從網(wǎng)卡發(fā)出,但是我們?nèi)匀粺o(wú)法判斷當(dāng)前的網(wǎng)絡(luò)利用率是 100% 還是 1%媚朦,我們僅僅能夠知道目前有流量氧敢。這僅僅是在不知道網(wǎng)絡(luò)包大小的情況下能夠得到的結(jié)論。簡(jiǎn)單的說(shuō)我們無(wú)法通過(guò) Linux 和 Solaris 提供的 Netstat 來(lái)判斷當(dāng)前網(wǎng)絡(luò)是否影響了性能询张。我們需要一些其他的工具在我們的 Java 應(yīng)用運(yùn)行的過(guò)程中來(lái)監(jiān)測(cè)網(wǎng)絡(luò)孙乖。

5.磁盤(pán) I/O

如果應(yīng)用有對(duì)磁盤(pán)進(jìn)行操作,我們需要對(duì)磁盤(pán)進(jìn)行監(jiān)控份氧,來(lái)監(jiān)測(cè)可能出現(xiàn)的磁盤(pán)性能問(wèn)題唯袄。一些應(yīng)用是 I/O 密集型的,比如數(shù)據(jù)庫(kù)蜗帜。磁盤(pán)的使用通常還存在于應(yīng)用日志系統(tǒng)恋拷,日志通常是我們用來(lái)記錄系統(tǒng)運(yùn)行過(guò)程中重要信息的。

OneAPM for Java 能夠深入到所有 Java 應(yīng)用內(nèi)部完成應(yīng)用性能管理和監(jiān)控厅缺,包括代碼級(jí)別性能問(wèn)題的可見(jiàn)性蔬顾、性能瓶頸的快速識(shí)別與追溯、真實(shí)用戶體驗(yàn)監(jiān)控男杈、服務(wù)器監(jiān)控和端到端的應(yīng)用性能管理盐股。想閱讀更多技術(shù)文章伏穆,請(qǐng)?jiān)L問(wèn) OneAPM 官方博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末舷胜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子活翩,更是在濱河造成了極大的恐慌烹骨,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,843評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纱新,死亡現(xiàn)場(chǎng)離奇詭異展氓,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)脸爱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)遇汞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事空入÷缢” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,187評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵歪赢,是天一觀的道長(zhǎng)化戳。 經(jīng)常有香客問(wèn)我,道長(zhǎng)埋凯,這世上最難降的妖魔是什么点楼? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,264評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮白对,結(jié)果婚禮上掠廓,老公的妹妹穿的比我還像新娘。我一直安慰自己甩恼,他們只是感情好蟀瞧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著条摸,像睡著了一般悦污。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上钉蒲,一...
    開(kāi)封第一講書(shū)人閱讀 51,231評(píng)論 1 299
  • 那天切端,我揣著相機(jī)與錄音,去河邊找鬼子巾。 笑死帆赢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的线梗。 我是一名探鬼主播椰于,決...
    沈念sama閱讀 40,116評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼仪搔!你這毒婦竟也來(lái)了瘾婿?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,945評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤烤咧,失蹤者是張志新(化名)和其女友劉穎偏陪,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體煮嫌,經(jīng)...
    沈念sama閱讀 45,367評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡笛谦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了昌阿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饥脑。...
    茶點(diǎn)故事閱讀 39,754評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡恳邀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出灶轰,到底是詐尸還是另有隱情谣沸,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評(píng)論 5 344
  • 正文 年R本政府宣布笋颤,位于F島的核電站乳附,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏伴澄。R本人自食惡果不足惜赋除,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望秉版。 院中可真熱鬧贤重,春花似錦、人聲如沸清焕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,692評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)秸妥。三九已至,卻和暖如春沃粗,著一層夾襖步出監(jiān)牢的瞬間粥惧,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,842評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工最盅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留突雪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,797評(píng)論 2 369
  • 正文 我出身青樓涡贱,卻偏偏與公主長(zhǎng)得像咏删,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子问词,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,085評(píng)論 25 707
  • 從三月份找實(shí)習(xí)到現(xiàn)在督函,面了一些公司,掛了不少激挪,但最終還是拿到小米辰狡、百度、阿里垄分、京東宛篇、新浪、CVTE薄湿、樂(lè)視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,243評(píng)論 11 349
  • 這篇文章節(jié)選自《java performance》叫倍,對(duì)java性能比較關(guān)心的同學(xué)大概都知道這本書(shū)偷卧,性能這個(gè)東西可能...
    Bugtags閱讀 254評(píng)論 0 1
  • 夢(mèng)得傅說(shuō),囊血射天段标,酒池肉林涯冠,比干剖心 夢(mèng)得傅說(shuō) 譯文:商王武丁夢(mèng)到了那個(gè)輔佐自己的人,他的名字叫傅說(shuō)(“說(shuō)”在這...
    書(shū)山尋路閱讀 557評(píng)論 0 3
  • 坐在回家路上的公交逼庞,又一次思緒萬(wàn)千蛇更,一瞬間感覺(jué)想通了很多事。從一個(gè)衣食無(wú)憂赛糟,不管不顧派任,高中了老爸還負(fù)責(zé)我的...
    方小信閱讀 171評(píng)論 0 0