<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>


    posts - 15,  comments - 34,  trackbacks - 27

    關注性能: 調優垃圾收集

    將 100 MB 的垃圾打包成 50 MB 的包

    developerWorks
    文檔選項
    將此頁作為電子郵件發送

    將此頁作為電子郵件發送

    未顯示需要 JavaScript 的文檔選項


    對此頁的評價

    幫助我們改進這些內容


    級別: 初級

    Jack Shirazi, 董事, JavaPerformanceTuning.com
    Kirk Pepperdine, CTO, JavaPerformanceTuning.com

    2004 年 7 月 30 日

    如果您是當前寫網志(blogging)狂熱者中的一員,則可能聽說過 Blog-City,這是由蘇格蘭的一家小公司 Blog-City Ltd. 擁有和運營的網志站點。當一些意料之外的性能問題突然出現時,Java 性能專家 Jack Shirazi 和 Kirk Pepperdine 被邀請幫助進行 Blog-City 的技術調整。他們的檢測工作因為受硬件約束和整個項目所使用的通信通道(IRC、ftp 和 偶爾的電子郵件)的限制而變得復雜。

    隨著網志作為公共日記的流行,網志主機迅速地增長。所以對于 Blog-City 的人來說,非常清楚他們的站點需要發展和提高。為了滿足其增長的需要,該公司最近剛剛推出了 Blog-City version 2.0。正像經常出現的情況那樣,當新的應用程序轉入運行階段時,由于各種原因,其性能無法完全滿足期望的要求,突然出現隨機的長時間應用程序被掛起的現象還不是最壞的情況。

    在其核心,Blog-City 依靠 Blue Dragon Servlet 引擎(CFML 引擎)和數據庫。令人驚訝的是,所有這些軟件都宿主在運行 Red Hat Linux 的相當老的 P3 機器上。這臺機器具有單個硬盤和 512MB 內存,這對于過去的負載來說是足夠強大的,但它正在承受不斷增長的負載。Blog-City 的運作方式很成功,但其資源限制卻成了其成功路上的絆腳石。盡管如此,這就是未來還要繼續使用一段時間的所有硬件。

    問題定義

    整個過程的第一步是確定突然出現應用程序減慢的原因。首先我們懷疑的對象是垃圾收集。正如我們在 本專欄的上月文章 中所論述的那樣,確定垃圾收集和內存利用問題是否對應用程序產生負面影響的最容易的方式是,設置 -verbose:gc JVM 選項,并檢查日志輸出。因此我們重新啟動應用程序,打開冗長的垃圾收集日志選項,然后耐心地等待應用程序的性能降低。我們的耐心換來的是非常詳細的垃圾收集日志文件。

    從對日志文件的最初分析中看,在這一應用程序中垃圾收集的瓶頸是顯而易見的。種種跡象包括垃圾收集的頻率、持續時間和總體效率都已表明這一點。高于普通垃圾收集頻率的常見原因是,堆的大小剛好足以適應所有當前正在使用的運行對象,無法適應新的正被創建的對象。雖然應用程序消耗大量堆可能有許多原因,但主要原因可能是沒有足夠內存而導致垃圾收集器運行,因為它設法滿足當前需要。換句話說,應用程序試圖分配新對象,但失敗了,如果失敗的話,將觸發垃圾收集程序。如果垃圾收集失敗而無法恢復足夠內存,它將迫使另一個花費更大的垃圾收集程序發生。即使 GC 恢復了足夠的空間來滿足瞬間需求,可以肯定的是,在應用程序程序另一次分配失敗,觸發另一個 GC 之前,時間不會很長。因此,應該關注重復掃描空閑堆空間的無效任務,而不是服務于應用程序的 JVM。

    應用程序逐步消耗所有可用的堆空間可能有許多原因,但如果有更多內存的話,臨時解決方案就是配置更大的堆。假設應用程序沒有內存泄漏(或者也就是我們常說的“無意識地保留對象”),它將找到一個“自然”級別的堆消耗,在這個級別中,GC 將能夠很適應地得到維持(除非對象創建的速度過快,以至 GC 總是處于賽跑狀態)。在這種情況下,以及無意識地保留對象的情況下,我們需要對應用程序做一些變動,以便獲得某些改進。



    回頁首


    如果僅僅是這樣,那就太簡單了

    遺憾的是,我們必須面對嚴酷的現實因素——正在運行的機器只有 512 MB 內存。更糟的是,我們必須與數據庫和其他運行在機器中的進程共享該空間。要完整理解這一點為什么至關重要,首先您必須明確理解垃圾收集的基本知識,以及它如何與底層操作系統進行交互。

    虛擬內存不再是靈丹妙藥

    操作系統已經使用虛擬內存許多年了。正如您所知道的,虛擬內存使操作系統的內存看起來比實際的內存要多,這允許計算機運行那些所需內存比可用物理內存更大的程序,不使用內存的應用程序部分將保存在磁盤上。為了進一步簡化,操作系統同時按頁管理內存。頁通常包含 512 字節到 8 KB,所有頁的組合就組成了一個虛擬地址空間。操作系統維持一個頁表,用于告訴操作系統如何映射虛擬地址到物理地址。當應用程序要求某個內存位置的內容時,操作系統(或硬件)將識別包含虛擬地址的頁面。然后確定該頁面是否在內存中,如果不在,將會報告 頁面錯誤。但是有許多種方式來處理頁面錯誤,最終的結果是,頁面必須從磁盤載入到內存中。這樣應用程序就可以訪問到有效虛擬地址的內容。

    如果相關對象總是在內存的同一頁面上聚合,那么 GC 的連續工作很可能出現困難。但是現實世界中,相關對象很少(如果有的話)出現聚合現象。實際結果是,依靠虛擬內存的系統將導致操作系統將頁從內存中換入和換出,因為它標記然后廢棄堆空間,而當聚合現象發生時,GC 將很多時間花在等待頁面從磁盤換入而不是實際恢復內存上。因此,應用程序正在等待 GC,而 GC 正在等待磁盤,其間未完成任何真正的工作。由于本系統只有一個磁盤,并且它還需要支持數據庫,因此我們在解決問題時處于兩難境地。一方面,我們需要增加內存數量,這樣我們可以減少 GC 的頻率,但另一方面,我們還需要確保數據庫的完好運行,而數據庫也是內存的消耗大戶。因此,我們需要了解應用程序所需的最小內存數量。

    正如我們在上月看到的,在冗長的 GC 日志中這一信息可以很容易得到,無需為這一信息而掃描整個日志,我們使用免費的 JTune 工具(請參閱 參考資料)來解釋冗長的 GC 日志。圖 1 顯示了經過垃圾收集之后的內存利用情況,其中我們將 -Xmx 設置為 256 MB。


    圖 1. 垃圾收集之后的內存利用情況
    圖 1. 垃圾收集之后的內存利用情況


    回頁首


    分析 verbose:gc 輸出

    在圖 1 中,藍色部分表示部分 GC。橙色區域表示完整的 GC,而粉色矩形表示兩個完整 GC 在它們之間少于一毫秒之內已經發生的堆利用情況。從結果中我們看到,平均每 0.257 秒有 12,823 次清除。總共有 345 次完整的垃圾收集和 44 次緊挨著的垃圾收集。完整垃圾收集的平均持續時間是 7.303 秒,結果表明有 9.36% 的運行時間花費在垃圾收集程序上。雖然這個值偏高,它仍然保持在 10% 的正常水平之內。因此,在本例中,GC 是系統的繁重負擔但還沒有達到嚴重的地步。真正的問題是存在內存泄漏,這一點可以從總體上堆利用率不斷增長的趨勢看出來。

    即使內存泄漏消耗了 50 MB 內存,它也應該是經過很長一段時間后才發生,這使得內存泄漏在較短的測試中很少會引人注意。內存泄漏的實際結果是,它把 JVM 的內存消耗推動到某個點,在該點它強迫 JVM (從而強迫操作系統)消耗內存,它強迫啟動分頁。圖 2 就證明了這一點。注意正好在 55,000 秒標記之后,每一 GC 周期的持續時間中內存消耗突然地持續增加。


    圖 2. GC 持續時間
    圖 2. GC 持續時間

    如您所想,由于垃圾收集的阻塞將導致系統只有更少的時間來分配給用戶線程,因此用戶響應開始增加。在日志的過去 10,000 秒中,我們看到每次完全收集(總共 15 次)花費時間超過了 30 秒,平均持續時間大約 70 秒 —— 這導致超過 10% 的處理時間分配給完全 GC。部分收集(這里剛好超過了 1000 次)無法正常工作,平均每次請求耗時 1.24 秒,遠高于以前 11,800 次清除中的平均 0.25 秒。

    分代收集

    本文不涉及太深的細節(請參閱 參考資料,獲取分代 GC 的詳細描述),分代堆空間產生了“年輕”和“年老”對象,它們位于分開的堆空間中。在本配置中,年輕和年老分代空間可以通過不同的 GC 算法和策略來維持,以提高 GC 的整體性能。

    一種這樣的策略是,進一步將年輕分代劃分為創建空間,稱為 Eden,以及殘存(survivor)空間,用于幸存一個或者多個收集的年輕對象。如果在 Eden 中有足夠的內存來適應新對象創建的話,這一般能工作正常。如果不是這種情況,那么對象可以在年老對象空間中創建。同樣,如果殘存空間足夠的話,那么對象將移入年老分代空間。我們將使用這些事實來幫助調優遇到的問題。



    回頁首


    減少完全收集的次數

    Blog-City 所碰到的難題是在某一隨機點出現長的暫停時間。一旦應用程序啟動出現問題,不重新啟動機器的話,就無法返回跟蹤。由于長時間暫停的現象直接與長的 GC 相關,我們考慮如果將對象保持在年輕分代來減少完全 GC 的次數。由于完全 GC 的代價如此之大,在年輕分代收集更多對象能夠得到更短的暫停時間。要完成這一任務,我們調整了一些垃圾收集參數,包括 殘存比率(survivor ratio)期限閾值(tenuring threshold)

    殘存比率用于設置與年輕分代空間總體大小相關的殘存空間的大小。如果殘存比率設置為 8(Intel 的默認值),那么每一殘存空間將是 Eden 空間的 1/8 大小。另一種考察它的方式是,年輕分代將該 Eden 空間劃分為 10 個相同大小的值,該 Eden 將分配其中的 8 個,每一個殘存空間的大小為 1。

    我們的假設是,通過減少殘存比率,我們可以減少由于殘存空間中空間的缺乏,對象過早地被提升為年老分代的幾率。另一種方法是增加期限閾值,這樣的話,對象在提升之前將需要保留更多的 GC 事件。本著這個想法,Blog-City 將設置更改為 -XX:SurvivorRatio=4 ,然后重新啟動。

    選擇低暫停時間的垃圾收集算法

    由于這次技術調優的目標之一是減少暫停時間,我們決定拋棄默認的單線程、標記清掃的垃圾收集程序。我們選擇通過標志 XX:+UseParallelGC 來采用并行拷貝收集程序。同樣,有關實際算法的細節可以在 Resources中找到,這里需要提一下的是,這一標志調用了一個多線程收集程序。線程的數量設置為 CPU 的數量。基于這一事實,了解為什么單線程并行拷貝垃圾收集程序要比傳統的標記清掃算法工作更好是很困難的,但是從實際觀察中可以體會到提供了某些性能上的優勢。

    圖 3 和圖 4 的輸出展示了使用標志 -XX:SurvivorRatio=4 +XX:+UseParallelGC -server -Xmx256M 運行時的結果。


    圖 3. 新配置下的內存使用情況
    圖 3. 新配置下的內存使用情況

    結果圖表顯示了明顯的不同。雖然仍然有一個內存漏洞。內存消耗的總數相比前一個圖已經是大大降低了。GC 持續時間的快速比較揭示了年輕分代和年老分代的總體 GC 持續時間的明顯減少。


    圖 4. 新配置下的 GC 持續時間
    圖 4. 新配置下的 GC 持續時間

    有意的、無意的對象保持

    由于應用程序是依靠內存的,跟蹤內存泄漏并消除它們已經變得越來越重要。在本例中,用于支持緩存策略的組件決定了主要漏洞的來源。從最后的內存分析情況來看(圖 3),雖然消除了主要內存泄漏,我們可以看到仍有另一個“低級別的”的漏洞,但這個漏洞比較小,因此它在下一版本發布之前可以忽略。



    回頁首


    結束語

    本文提出了許多挑戰。首先,我們正在調優一個現實中的應用程序,這意味著更改會受到很多限制。第二個挑戰是,這項任務是使用 IRC 聊天室遠程操控的。聊天室不提供任何級別或質量的相互通信,而通信在這種類型的任務中往往是必需的。在本例中,團隊已經習慣了聊天室的真實性,并能通過這種真實性毫無任何阻礙地工作著。

    最后也是最困難的挑戰是我們受硬件的限制。由于多種原因,我們不可能為系統添加新硬件。其中最大的問題是系統中物理內存的數量,而 JVM 和 MySQL 需要大量的內存。但是,通過系統地逐一應用許多更改,并度量它們對系統產生的影響,我們可以逐步地改進總體系統性能。



    回頁首


    參考資料



    回頁首


    作者簡介

    Jack Shirazi 是 JavaPerformanceTuning.com的董事和 Java Performance Tuning, 2nd Edition (O'Reilly) 一書的作者。


    Kirk Pepperdine is 是 Java Performance Tuning.com 的首席技術官(Chief Technical Officer,CTO),過去 15 年來他一直專攻對象技術和性能調優。Kirk 是 Ant Developer's Handbook (MacMillan) 一書的合著者。

    posted on 2005-12-29 13:56 jacky 閱讀(231) 評論(0)  編輯  收藏 所屬分類: java
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    常用鏈接

    留言簿(10)

    隨筆檔案

    文章分類

    文章檔案

    相冊

    收藏夾

    java

    搜索

    •  

    最新評論


    主站蜘蛛池模板: 免费无遮挡无码视频在线观看| 亚洲综合无码AV一区二区| a级毛片在线免费观看| 一级大黄美女免费播放| 国产精品免费看久久久 | 免费的黄网站男人的天堂| 国产青草视频免费观看97| 国产成人综合亚洲亚洲国产第一页| 精品视频免费在线| 国产午夜成人免费看片无遮挡| 日韩毛片免费无码无毒视频观看| 国产禁女女网站免费看| 特黄特色大片免费| 99久久免费国产香蕉麻豆| 四虎影在线永久免费四虎地址8848aa| 亚洲av永久无码精品网站| 亚洲AV日韩综合一区尤物| 精精国产www视频在线观看免费| 成人无码区免费A片视频WWW| 国产亚洲精AA在线观看SEE| 国产亚洲一卡2卡3卡4卡新区| 久久狠狠躁免费观看2020| 亚洲黄色高清视频| 人成电影网在线观看免费| 成人毛片18女人毛片免费| 亚洲av无码一区二区乱子伦as | 88av免费观看入口在线| 亚洲国产一成久久精品国产成人综合 | 911精品国产亚洲日本美国韩国| 67194熟妇在线永久免费观看| 亚洲精品无码成人| 9420免费高清在线视频| 亚洲中文字幕AV在天堂| 99热在线免费观看| 亚洲国产成人一区二区精品区| 国产亚洲午夜精品| 亚洲av无码精品网站| 成年大片免费视频| 精品一区二区三区免费观看| 亚洲第一香蕉视频| 人妻无码久久一区二区三区免费|