<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          JVM性能優(yōu)化內(nèi)幕-Java 性能工具箱

          共 4896字,需瀏覽 10分鐘

           ·

          2023-03-07 23:42

          性能分析討論的基礎(chǔ)是所有過程和信息的可見性,即要了解應(yīng)用程序內(nèi)部以及承載應(yīng)用程序運(yùn)行的環(huán)境中正在發(fā)生什么??梢娦缘年P(guān)鍵在于使用工具,所以性能優(yōu)化是圍繞工具展開的。

          在第 2 章中,我們探討了采用數(shù)據(jù)驅(qū)動(dòng)的方法進(jìn)行性能優(yōu)化的重要性:你必須測量應(yīng)用程序的性能并了解測量結(jié)果的意義。性能分析同樣必須由數(shù)據(jù)驅(qū)動(dòng):為了優(yōu)化應(yīng)用程序,你必須掌握有關(guān)應(yīng)用程序運(yùn)行的數(shù)據(jù)。如何獲取和理解這些數(shù)據(jù)是本章的主題。

          數(shù)以百計(jì)的工具可以提供 Java 應(yīng)用程序的運(yùn)行信息,但是研究所有的工具是不切實(shí)際的。最重要的工具大都是 Java 開發(fā)工具包(JDK)自帶的。盡管還有其他的開源工具和商用工具,但為方便起見,本章主要關(guān)注 JDK 工具。

          操作系統(tǒng)工具和分析

          性能分析的起點(diǎn)和 Java 無關(guān),而和操作系統(tǒng)自帶的一組基本監(jiān)控工具有關(guān)。在 Unix系統(tǒng)中,有 sarSystem AccountingReport)及其組成工具,例如 vmstat、iostat prstat 等。在 Windows 系統(tǒng)中,有圖形化的資源監(jiān)視器和類似 typeperf 的命令行工具。

          無論性能測試何時(shí)進(jìn)行,都需要從操作系統(tǒng)收集數(shù)據(jù)。至少要收集 CPU、內(nèi)存和磁盤使用率的相關(guān)信息。如果應(yīng)用程序使用了網(wǎng)絡(luò),也需要收集網(wǎng)絡(luò)使用率信息。如果是自動(dòng)化的性能測試,就需要使用命令行工具(甚至在 Windows 上也一樣)。即使測試以交互式運(yùn)行,最好也用命令行工具捕獲輸出,而不是盯著 GUI 圖表猜測它的意思。在之后進(jìn)行分析時(shí),隨時(shí)可以將捕獲的輸出以圖表的方式展現(xiàn)出來。

          CPU 使用率

          我們首先來看 CPU 監(jiān)控,看看從中可以得到關(guān)于 Java 應(yīng)用程序的哪些信息。CPU 使用率通常分為兩類:用戶時(shí)間和系統(tǒng)時(shí)間(Windows 上叫作特權(quán)時(shí)間)。用戶時(shí)間指的是 CPU執(zhí)行應(yīng)用程序代碼的時(shí)間所占的百分比,系統(tǒng)時(shí)間則是執(zhí)行內(nèi)核代碼的時(shí)間所占的百分比。系統(tǒng)時(shí)間和應(yīng)用程序相關(guān)。如果應(yīng)用程序執(zhí)行 I/O 操作,那么系統(tǒng)將執(zhí)行內(nèi)核代碼,從磁盤讀取文件,或者將緩沖的數(shù)據(jù)發(fā)送給網(wǎng)絡(luò)。任何使用底層系統(tǒng)資源的操作都會(huì)讓應(yīng)用程序使用更多的系統(tǒng)時(shí)間。

          性能優(yōu)化的目標(biāo)是,在盡可能短的時(shí)間內(nèi),讓 CPU 使用率盡可能高。這聽起來有點(diǎn)違反常理,因?yàn)槟憧隙ㄓ羞^這樣的經(jīng)歷:CPU 使用率到了 100% 之后,你只能坐在計(jì)算機(jī)屏幕前看著它掙扎。接下來讓我們看看 CPU 使用率到底意味著什么。

          首先需要牢記的是,CPU 使用率是一段時(shí)間內(nèi)的平均值,也許是 5 秒、30 秒,甚至可能是1 秒(不會(huì)比它還短了)。假設(shè)在執(zhí)行一個(gè)應(yīng)用程序的 10 分鐘內(nèi),CPU 使用率平均是50%,這意味著 CPU 有一半時(shí)間是空閑的。如果優(yōu)化這個(gè)應(yīng)用程序以避免出現(xiàn)空閑時(shí)間(在沒有其他瓶頸的情況下),那么這樣做能讓它的性能翻倍,即以 100% CPU 使用率5 分鐘內(nèi)結(jié)束運(yùn)行。

          如果我們優(yōu)化這個(gè)應(yīng)用程序的算法并讓其性能再次翻倍,那么它會(huì)以 100% CPU 使用率2.5 分鐘內(nèi)結(jié)束運(yùn)行。CPU 使用率反映了應(yīng)用程序使用 CPU 的效率,所以這個(gè)數(shù)字越大,性能就越好。如果我在 Linux 桌面系統(tǒng)上運(yùn)行 vmstat 1,會(huì)得到如下的幾行輸出(每秒一行):

          這個(gè)例子中運(yùn)行的應(yīng)用程序只有一個(gè)活躍線程,這使得例子更易于理解,不過即使有多個(gè)線程,概念仍然適用。

          在每秒內(nèi),CPU 忙碌 450 毫秒(42% 的時(shí)間執(zhí)行用戶代碼,3% 的時(shí)間執(zhí)行系統(tǒng)代碼)。相應(yīng)地,CPU 空閑 550 毫秒。CPU 空閑可能是由于以下原因。應(yīng)用程序阻塞在同步原語上,直到鎖釋放后才能繼續(xù)執(zhí)行。

          應(yīng)用程序在等待某些東西,比如數(shù)據(jù)庫調(diào)用返回的響應(yīng)。應(yīng)用程序沒有事情可做。

          前兩種情況往往表明問題可以解決。如果可以減少鎖的競爭或者優(yōu)化數(shù)據(jù)庫以使響應(yīng)返回得更快,應(yīng)用程序就會(huì)運(yùn)行得更快,平均 CPU 使用率也會(huì)上升(當(dāng)然,此處假設(shè)沒有其他類似問題會(huì)阻塞應(yīng)用程序)。

          3 種情況常常使人困惑。如果應(yīng)用程序有事可做(而且沒有等待鎖或其他資源),那么CPU 必然會(huì)分配一些周期執(zhí)行應(yīng)用程序的代碼。這是一個(gè)通用原則,并不局限于 Java。例如你寫了一個(gè)包含無限循環(huán)的簡單腳本,腳本執(zhí)行時(shí)會(huì)消耗 100% CPU 資源。下面的Windows 批處理任務(wù)就是這么做的:

          試想一下,腳本沒有消耗 100% CPU 資源意味著什么。這意味著操作系統(tǒng)還可以做其他的事——比如可以打印另一行 LOOPING——但是它選擇空閑??臻e在這種情況下并沒有什么幫助,如果正在進(jìn)行有用卻很耗時(shí)的計(jì)算,那么強(qiáng)制 CPU 周期性地空閑會(huì)讓我們得到答案的時(shí)間變得更長。

          如果你在單 CPU 機(jī)器上或者容器中運(yùn)行這個(gè)腳本,那么多數(shù)時(shí)候你不會(huì)注意到它在運(yùn)行。但是,如果嘗試啟動(dòng)一個(gè)新的應(yīng)用程序,或者測試另一個(gè)應(yīng)用程序的性能,你就會(huì)注意到影響了。操作系統(tǒng)會(huì)為競爭 CPU 周期的應(yīng)用程序分配時(shí)間片,但是新應(yīng)用程序的可用 CPU 期較少,所以就會(huì)運(yùn)行得很慢。有經(jīng)驗(yàn)的人有時(shí)認(rèn)為,留下一些空閑的 CPU 周期是件好事,以備不時(shí)之需。

          但是操作系統(tǒng)不會(huì)猜測你下一步要做什么,它默認(rèn)會(huì)執(zhí)行任何可以執(zhí)行的應(yīng)用程序,而不是CPU 空閑。限制程序使用 CPU盡可能地利用 CPU 周期運(yùn)行程序,可以最大化程序的性能。不過,有時(shí)你可能并不想這么做。比如,運(yùn)行 SETI@home 時(shí),它會(huì)消耗機(jī)器上所有可用的 CPU 周期。在你不工作或者僅僅瀏覽網(wǎng)頁和編寫文檔時(shí)還好,否則這會(huì)降低你的生產(chǎn)率。(我們還沒考慮你在玩 CPU 密集型游戲時(shí)會(huì)發(fā)生什么?。?/span>

          有許多與操作系統(tǒng)相關(guān)的機(jī)制可以人為地限制程序使用 CPU——實(shí)際上,就是強(qiáng)制CPU 留下空閑周期,以防有程序需要使用。也可以更改進(jìn)程的優(yōu)先級(jí),這樣一來,后臺(tái)任務(wù)就不會(huì)和你想運(yùn)行的程序爭奪 CPU 周期,也不會(huì)留下空閑的 CPU 周期。這些技術(shù)不在我們現(xiàn)在的討論范圍內(nèi)。(順便說一句,SETI@home 允許你對(duì)這些進(jìn)行配置,它不會(huì)真的占用機(jī)器上所有的空閑周期,除非你告訴它這么做。)

          01. Java 和單 CPU 的使用率

          我們?cè)倩氐?Java 應(yīng)用程序的討論,上述例子中的 CPU 周期性空閑意味著什么?這取決于應(yīng)用程序的類型。如果應(yīng)用程序?qū)儆谂幚眍愋?,那么其要完成的工作量是?/span>定的。這種情況下,你不會(huì)看到 CPU 空閑,因?yàn)?CPU 空閑意味著無事可做。對(duì)批處理任務(wù)而言,榨干 CPU 的最后一點(diǎn)處理能力是其孜孜以求的目標(biāo)。用得越多,任務(wù)完成的速度越快。即便 CPU 使用率已經(jīng)達(dá)到 100%,你依然可以探索進(jìn)一步優(yōu)化的可能,從而讓工作更快完成(同時(shí)盡量保持 100% CPU 使用率)。

          如果應(yīng)用程序是服務(wù)器處理類型,即應(yīng)用程序需要從某處接收請(qǐng)求,那么 CPU 會(huì)因為沒有工作可做而處于空閑狀態(tài)。例如,Web 服務(wù)器已經(jīng)處理了所有的 HTTP 請(qǐng)求,正在等待下一個(gè)請(qǐng)求。這時(shí)就要引入平均時(shí)間。前面 vmstat 樣例的輸出是從服務(wù)器獲取的,服務(wù)器每秒接收一個(gè)請(qǐng)求。應(yīng)用程序服務(wù)器處理請(qǐng)求的時(shí)間為 450毫秒——在這 450 毫秒內(nèi),CPU100% 忙碌,而剩下 550 毫秒空閑。這會(huì)報(bào)告為CPU 45% 忙碌的。

          盡管 CPU 忙碌時(shí)間常常因?yàn)榱6忍《鵁o法可視化,但運(yùn)行有負(fù)載的應(yīng)用程序時(shí),CPU 就是這樣以短時(shí)突發(fā)的方式運(yùn)行的。如果 CPU 每半秒接收一個(gè)請(qǐng)求且請(qǐng)求的平均處理時(shí)間是 225 毫秒,那么也可以在宏觀層面看到同樣的模式。CPU 會(huì)忙碌 225毫秒,空閑 275 毫秒,再次忙碌 225 毫秒,再次空閑 275 毫秒:平均來說,45% 時(shí)間忙碌,55% 的時(shí)間空閑。

          如果應(yīng)用程序優(yōu)化之后每個(gè)請(qǐng)求只需要 400 毫秒,那么總體的 CPU 使用率會(huì)降低至40%。這是唯一降低 CPU 使用率有意義的情況——流入系統(tǒng)的負(fù)載量固定且應(yīng)用程序不受限于外部資源。同時(shí),這些優(yōu)化可以讓系統(tǒng)承擔(dān)更多的負(fù)載,最終提高 CPU使用率。在微觀層面,這種優(yōu)化仍然只是在短時(shí)間(執(zhí)行請(qǐng)求的 400 毫秒)內(nèi)讓CPU 使用率達(dá)到 100%——只是 CPU 峰值的維持時(shí)間太短,不足以讓大多數(shù)工具顯示為 100% 使用率。02. Java 和多 CPU 的使用率上述例子假設(shè)在單 CPU 機(jī)器上運(yùn)行單個(gè)線程,一般情況下,這與多 CPU 多線程是相通的。多線程會(huì)以有趣的方式使平均 CPU 使用率偏斜——5 章就有這樣的例子,它展示了多個(gè) GC 線程對(duì) CPU 使用率的影響。但總體來說,在多 CPU 機(jī)器上運(yùn)行多線程的目標(biāo)仍然是通過確保單個(gè)線程不被阻塞而提升 CPU 使用率,或者是在線程已經(jīng)完成工作,正在等待更多的工作時(shí),降低 CPU 使用率(在很長的時(shí)間間隔內(nèi))。

          在多 CPU 多線程的情況下,還有一個(gè)關(guān)于 CPU 何時(shí)空閑的重要補(bǔ)充:CPU 在有工作可做時(shí)也可能空閑。如果沒有處理那項(xiàng)工作的可用線程,這種情況就會(huì)發(fā)生。典型的情況是,應(yīng)用程序以固定大小的線程池運(yùn)行各種任務(wù)。線程任務(wù)以隊(duì)列形式放置,當(dāng)有線程空閑而且隊(duì)列中有任務(wù)時(shí),該線程會(huì)取出任務(wù)并執(zhí)行。然而,每個(gè)線程一次只能執(zhí)行一個(gè)任務(wù),如果該任務(wù)被阻塞(例如,等待數(shù)據(jù)庫的響應(yīng)),那么該線程在這期間無法執(zhí)行新的任務(wù)。此時(shí),有任務(wù)要執(zhí)行(有工作要完成)但是沒有可用的線程來執(zhí)行它們,結(jié)果就是 CPU 空閑。

          在這個(gè)具體的例子中,應(yīng)該增加線程池的大小。但是,不要僅僅因?yàn)橛锌臻e的 CPU可用,就認(rèn)為應(yīng)該增加線程池的大小以完成更多的工作。程序無法獲得 CPU 周期,還有我們之前提到過的兩個(gè)原因——鎖或外部資源的瓶頸。在確定行動(dòng)方案之前,了解程序?yàn)槭裁礇]有獲得 CPU 很重要。(有關(guān)這一主題的更多詳細(xì)信息,請(qǐng)參見第9 章。)

          查看 CPU 使用率是了解程序性能的第一步,但這僅僅是看看代碼是否使用了所有可用的 CPU 資源,或者看看是否出現(xiàn)了同步問題或資源問題。

          CPU 運(yùn)行隊(duì)列

          Windows 系統(tǒng)和 Unix系統(tǒng)都可以監(jiān)控運(yùn)行(意味著它們沒有被 I/O 阻塞或者休眠)的線程數(shù)。Unix系統(tǒng)稱之為運(yùn)行隊(duì)列,許多工具的輸出包含運(yùn)行隊(duì)列的長度。3.1.1 節(jié)中的vmstat 的輸出就包含這一數(shù)值:每行第一個(gè)數(shù)字就是運(yùn)行隊(duì)列的長度。Windows 系統(tǒng)稱之為處理器隊(duì)列,可以用 typeperf 命令查看(還有其他方式):

          這個(gè)輸出和之前的輸出的重要區(qū)別是:在 Unix系統(tǒng)中,運(yùn)行隊(duì)列的長度(vmstat 示例輸出中的 1 2)指的是,正在運(yùn)行的線程的數(shù)量加上一旦 CPU 可用就可以運(yùn)行的線程的數(shù)量。在示例中,總是有至少 1 個(gè)線程試圖運(yùn)行,即以單線程執(zhí)行應(yīng)用程序。因此,運(yùn)行隊(duì)列的長度至少是 1。記住,運(yùn)行隊(duì)列表示的是機(jī)器上所有的進(jìn)程信息,所以有時(shí)其他線程(完全不同的進(jìn)程)也試圖運(yùn)行,這就是為什么示例輸出中的運(yùn)行隊(duì)列長度有時(shí)是 2。

          Windows 系統(tǒng)中,處理器隊(duì)列長度不包含正在運(yùn)行的線程的數(shù)量。因此在 typeperf 樣例輸出中,處理器隊(duì)列的長度是 0,即便機(jī)器上運(yùn)行的是同一個(gè)單線程應(yīng)用程序,而且其中的線程始終在運(yùn)行。

          如果要運(yùn)行的線程數(shù)量多于可用的 CPU,性能就會(huì)開始下降??傮w來說,為確保性能,你需要讓 Windows 系統(tǒng)的處理器隊(duì)列長度等于 0,或者讓 Unix系統(tǒng)的運(yùn)行隊(duì)列長度小于等于CPU 數(shù)。這不是一條硬性規(guī)定,系統(tǒng)進(jìn)程和其他進(jìn)程會(huì)定期地暫時(shí)提高這個(gè)值,這不會(huì)對(duì)性能產(chǎn)生重大影響。但是如果運(yùn)行隊(duì)列在相當(dāng)長的時(shí)間內(nèi)過長,那就說明機(jī)器已經(jīng)過載,你需要想辦法減少機(jī)器當(dāng)前的工作量(通過將任務(wù)移至其他機(jī)器或者優(yōu)化代碼)。

          快速小結(jié)

          查看應(yīng)用程序性能時(shí),首先應(yīng)該考察的就是 CPU 時(shí)間。優(yōu)化代碼的目的是提高 CPU 使用率(在較短時(shí)間內(nèi)),而不是降低。在著手深入優(yōu)化應(yīng)用程序之前,應(yīng)該先弄清楚 CPU 使用率為什么低。

          本文就是愿天堂沒有BUG給大家分享的內(nèi)容,大家有收獲的話可以分享下,想學(xué)習(xí)更多的話可以到微信公眾號(hào)里找我,我等你哦。

          瀏覽 50
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲天堂成人 | 青娱乐福利视频 | 免费看无码一级A片放24小时 | 色色色色五月天 | 国产精品久久久久久久久AV竹菊 |