程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 深入了解Java 5.0的垃圾收集

深入了解Java 5.0的垃圾收集

編輯:關於JAVA

內存管理是影響軟件應用程序性能的一個重要因素。與實際的數據計算時間相比,分配和卸載內存所用的時間更長。

 

  雖然C++可對內存分配與釋放進行直接控制,Java利用垃圾收集來回收程序不再需要的內存,試圖掌握內存管理。但是,在需要實時性能時,與垃圾收集有關的“暫停”一直是人們反對應對Java的中心論點。

 

  垃圾收集是一個周期性的過程,它中斷程序的正常執行,分析對象引用,並回收被分配但不再被引用訪問的內存。在大型Java應用程序中,垃圾收集暫停可能持續幾秒鐘,這段時間足以中斷任何類型的實時通信或控制系統。

 

  因此,垃圾收集提供的內存提取要求一些開發者更仔細地考慮內存管理問題。即使Java並沒有提供和C++同等級別的內存分配控制,編程模式仍然會對Java應用程序的內存性能產生重大影響。

 

  在本文中,我將簡單回顧一下Java 5.0的垃圾收集調整功能。

 

  Java 5.0垃圾收集原理

 

  Java 1.5新特性??工效學??的目標是通過最少的命令行調整,為JVM提供優良的性能。工效學試圖為一個應用程序選擇最佳的垃圾收集器、堆大小與運行時間編譯器。

 

  垃圾收集器的選擇何時會對用戶產生影響呢?對許多應用程序來說,它根本沒有影響。也就是說,在垃圾收集產生的暫停的頻率與持續時間適度的情況下,應用程序可在其規范內執行。如果一個大型應用程序出現擴充,產生大量線程、處理器、套接字和許多內存,就會出現例外。

 

  如果一個對象再也不能通過運行程序中的任何指針到達,則視其為垃圾。最直接的垃圾收集運算法則簡單地在每個可到達的對象間迭代。那麼,剩下的對象即為垃圾。這一方法所用的時間與活動對象的數目成比例關系,且禁止用於維護許多活動數據的大型應用程序。

 

  從Java 2開始,虛擬機合並了許多應用分代收集組合的各種收集運算法則。盡管簡單的垃圾收集檢查堆中的每一個活動對象,但分代收集利用多數應用程序的幾個憑經驗觀察得到的特性來避免額外工作。這些觀察得到的特性中最為重要的一個就是所謂的早期失效率。許多對象分配以後很快“已經死亡”。例如,迭代器對象僅在單獨循環中存活。為優化這種情況,我們對內存進行分代管理,或在內存池中保留不同年齡的對象。當一代裝滿時,就對這個代進行垃圾收集。對象被分配到更年齡對象代,或新生代中。由於早期失效率,多數對象在那裡死亡。

 

  如果垃圾收集器成為瓶頸,你可能希望自定義代的大小。詳細檢查垃圾收集器的輸出,然後探究單個性能計量單位對垃圾收集器參數的靈敏度。

 

  初始化時,保留一個最大的地址空間,在必要時才分配給物理內存。為對象內存保留的全部地址空間可分為新生代和舊生代。新生代由eden和兩個生存空間組成。對象最初分配到eden中。任何時候,一個生存空間為空,並作為下一個空間的目的地,在eden與另一個生存空間中復制活動對象的集合。對象以這種方式在生存空間中復制,直到它們老化,或復制到舊生代中。與舊生代關系密切的第三個代稱為永生代。這是一個特別的代,因為它保留虛擬機所需要的數據,來描述在Java語言中沒有等同物的對象。例如,描述類與方法的對象存儲在永生代中。

 

  性能因素

 

  Java應用程序(特別是垃圾收集)有兩個性能計量單位:吞吐量與暫停。吞吐量是指在一段較長時間內,沒有用於垃圾收集的時間百分比。吞吐量包括用於分配的時間(但用於調整分配速度的時間一般不包括在內)。暫停是應用程序因為垃圾收集而出現的停頓時間。

 

  一些用戶還對其他因素較為敏感。例如,占用率(footprint) 是一批工作進程的集合,以頁和緩沖行數計量,在物理內存有限或者有很多進程的系統中,占用率可表示擴展性。

 

  反應性(Promptness)是對象死去的時間和內存變為可用時的時間差,是分布系統,包括遠程方法調用(RMI)中的重要因素。

 

  通常來說,特定的代大小選擇這些因素之間的平衡作用。例如,一個非常大的新生代的吞吐量可以最大,但這要以犧牲占用率、反應性和暫停時間為代價。你也可以犧牲吞吐量,應用一個小型的新生代來使新生代暫停時間最短。

 

  如果你希望提高有大量處理器的應用程序的性能,你應該使用吞吐量收集器。你可以用命令行標記-XX:+UseParallelGC來激活吞吐量收集器。你可以用ParallelGCThreads選項-XX:ParallelGCThreads=來控制垃圾收集器線程的數量。

 

  最大暫停時間目標用命令行標記-XX:MaxGCPauseMillis=來指定,這是對吞吐量收集器的一個暗示,即它需要毫秒或更短的暫停時間。存在有許多調整代大小的選項,如-XX:YoungGenerationSizeIncrement=用於新生代;而-XX:TenuredGenerationSizeIncrement=用於舊生代。

 

  如果應用程序受益於較短的垃圾收集器暫停,且能夠在應用程序運行時與垃圾收集器共享處理器資源,我建議使用並行低暫停收集器。如果舊生代占用率超出初始占用率(即當前堆的百分比用於並發收集啟動之前),並發收集將啟動。

 

  默認的初始占用率約為68%.你可以用參數-XX:CMSInitiatingOccupancyFraction=進行設置,這裡的是當前舊生代大小百分比。你能夠以並發階段遞增完成的方式使用並發收集器。這種模式(這裡稱之為“i-cms”)將收集器並發完成的工作分割成時間小段,安排在新生代收集之間。當需要並發收集器提供短暫停時間的應用程序在擁有少量處理器的機器上運行時,這一特性很有幫助。

 

  微調垃圾收集

 

  命令行參數-verbose:gc打印每個收集階段的信息。如果打開此參數,你會在每個垃圾收集階段看到相似的輸出結果。例如:

 

  [GC 325407K->83000K(776768K), 0.2300771 secs]

 

  [GC 325816K->83372K(776768K), 0.2454258 secs]

 

  [Full GC 267628K->83769K(776768K), 1.8479984 secs]

 

  有兩個次要收集和一個主要收集(完全GC)。標記-XX:+PrintGCDetails打印收集的其他信息。標記-XX:+PrintGCTimeStamps打印每次收集開始的時間。列表A是兩個標記被設定後的結果。

 

  另外,主要收集的信息由舊生代描述。在這裡,舊生代使用率減少到約10%,所用時間約為0.13秒。

 

  許多參數影響代的大小。在虛擬機的初始階段,堆的整個空間被保留。你可以用-Xmx選項指定保留空間的大小。如果-Xms參數的值小於-Xmx參數的值,表示不是所有的保留空間立即提交給虛擬機。堆的不同部分(永生代、舊生代和新生代)必要時可能會超出虛擬空間的限制。

 

  默認情況下,在每次收集時,虛擬機增大或縮小堆的大小,努力將自由空間與活動對象的比例保持在一個特定的范圍內。這個范圍是一個百分數,由參數-XX:MinHeapFreeRatio=和-XX:MaxHeapFreeRatio=設定,-Xms為下限,-Xmx為上限。除非有暫停問題,否則向虛擬機許可盡可能多的內存。默認的大小(64MB)一般都太小。你可以在Sun網站找到其他VM選項的說明。

 

  你還可以為新生代的堆設定一個比例。新生代越大,次要收集就越少發生。但是,在一個有限大小的堆中,新生代越大就意味著舊生代越小,這會增加主要收集的頻率。最優選擇要根據應用程序分配的對象的壽命分配來決定。

 

  新生代的大小由NewRatio控制。例如,設定-XX:NewRatio=3說明新生代與舊生代之比為1:3.如果希望的話,可用參數SurvivorRatio來調整生存空間的大小,但它並不如性能重要。

 

  例如,-XX:SurvivorRatio=6說明每個生存空間與eden的比為1:6.除非你發現過多主要收集或暫停時間問題,向新生代許可大量內存。

 

  Java 5.0執行了三個不同的垃圾收集器。吞吐量收集器使用新生代收集器的並行版本。如果-XX:+UseParallelGC選項傳遞給命令行,則使用並行收集器;如果-Xincgc或-XX:+UseConcMarkSweepGC選項傳遞給命令行,則使用並發收集器。

 

  在這種情況下,收集過程中應用程序會出現短期暫停。如果-XX:+UseTrainGC傳遞經命令行,則使用遞增式低暫停收集器。將來版本將不支持這一功能,但如果你想了解更多信息,請訪問Sun的關於應用這個收集器的文件資料。(提示:不要同時使用-XX:+UseParallelGC和-XX:+UseConcMarkSweepGC.)

 

  結論

 

  根據應用程序的需求,垃圾收集可能成為各種應用程序的瓶頸。通過了解應用程序需求與垃圾收集選項,可以減輕垃圾收集的影響。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved