內存管理是影響軟件應用程序性能的一個重要因素。與實際的數據計算時間相比,分配和卸載內存所用的時間更長。
雖然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)中的重要因素。
通常來說,特定的代大小選擇這些因素之?