《轉載》JVM垃圾回收機制

本文轉載自ImportNew - 鄭雯html

每一個Java程序員早晚都會碰到下面這個錯誤:java

  • java.lang.OutOfMemoryError

這個時候通常會建議採用以下方式解決這個錯誤:程序員

  • 增長MaxPermSize值
  • 增長最大堆內存到512M(-xmx參數)

這篇文章會具體介紹Java堆空間和參數MaxPermSize的含義。這篇文章涉及下列主題,並採用Hotspot JVM:web

  • 垃圾回收器(Garbage Collector,GC)
  • 哪一個JVM?
  • JVM命令行選項

 

垃圾回收器算法

垃圾回收器負責:服務器

  • 分配內存
  • 保證全部正在被引用的對象還存在於內存中
  • 回收執行代碼已經再也不引用的對象所佔的內存

 

應用執行時,定位和回收垃圾對象的過程會佔用總執行時間的將近25%,這會拖累應用的執行效率。oracle

JVM Generational GC

Hotspot VM提供的垃圾回收器是一個分代垃圾回收器(Generational GC)[9,16,18]-將內存劃分爲不一樣的階段,也就是說,不一樣的生命週期的對象放置在不一樣的地址池中。這樣的設計是基於弱年代假設(Weak Generational Hypothesis):jvm

1.越早分配的對象越容易失效;jsp

2.老對象不多會引用新對象。性能

 

這種分代方式能夠減小垃圾回收的停頓時間以及大範圍對象的回收成本。Hotspot VM將其堆空間分爲三個分代空間:

1. 年輕代Young Generation

○     Java應用在分配Java對象時,這些對象會被分配到年輕代堆空間中去

○     這個空間大可能是小對象而且會被頻繁回收

○     因爲年輕代堆空間的垃圾回收會很頻繁,所以其垃圾回收算法會更加劇視回收效率

2. 年老代Old Generationn

○     年輕代堆空間的長期存活對象會轉移到(也許是永久性轉移)年老代堆空間

○     這個堆空間一般比年輕代的堆空間大,而且其空間增加速度較緩

○     因爲大部分JVM堆空間都分配給了年老代,所以其垃圾回收算法須要更節省空間,此算法須要可以處理低垃圾密度的堆空間

3. 持久代Permanent Generation

○     存放VM和Java類的元數據(metadata),以及interned字符串和類的靜態變量

 

次收集(Minor GC)和全收集(Full GC

當這三個分代的堆空間比較緊張或者沒有足夠的空間來爲新到的請求分配的時候,垃圾回收機制就會起做用。有兩種類型的垃圾回收方式:次收集和全收集。當年輕代堆空間滿了的時候,會觸發次收集將還存活的對象移到年老代堆空間。當年老代堆空間滿了的時候,會觸發一個覆蓋全範圍的對象堆的全收集。

 

次收集

  • 當年輕代堆空間緊張時會被觸發
  • 相對於全收集而言,收集間隔較短

全收集

  • 當老年代或者持久代堆空間滿了,會觸發全收集操做
  • 可使用System.gc()方法來顯式的啓動全收集
  • 全收集通常根據堆大小的不一樣,須要的時間不盡相同,但通常會比較長。不過,若是全收集時間超過3到5秒鐘,那就太長了[1]

 

全收集一般時間最長,而且是程序沒法延遲執行或者沒法達到吞吐量目標的主因。GC的目標是去減小程序運行過程當中垃圾回收的頻率。爲了達到這個目的,能夠從這兩方面入手:

  • 從系統方面考慮:

○    儘可能採用大堆,可是不要大到須要系統從磁盤上「換」頁。通常而言,可用的RAM(沒有被系統進程佔用的)的80%都應該分配給JVM。

○    Java堆空間越大,垃圾回收器和java應用在吞吐量(throughput)和延遲執行(latency)方面的效果越好。

  • 從應用方面考慮:

○    減小對象分配(object allocations)操做,或者採用對象保留(object retention)方式有助於減少存活的數據大小,這也能夠反過來幫助垃圾回收作的更好。

○    參考這篇文章—Java性能提高竅門[19]

 

內存溢出錯誤(OutOfMemoryError

可怕的內存溢出錯誤是Java程序員最不肯意看到的。然而這個錯誤仍是會出現,尤爲應用中涉及到大量的數據處理時,或應用運行時間過長時。

一個應用所佔內存大小包括:

  • Java堆大小
  • 線程棧
  • I/O緩衝區
  • 原生庫所分配的內存

 

當一個應用耗盡了內存而且JVM GC也沒法回收任何對象空間的時候,就會發生內存溢出錯誤。可是,內存溢出錯誤並不必定就意味着內存泄露(memory leak)。也有可能只是一個配置問題,例如設置的堆大小(若是沒有設置那就是缺省的堆大小)對於應用來講是不夠用的。

 

JVM命令行參數

不管是客戶端應用仍是服務器端應用,一旦系統運行緩慢而且垃圾回收所佔時間過長,你就會但願經過調整堆大小來改善這一點。不過,爲了避免影響其餘也跑在同一個系統中的應用,不該該將堆大小設置的過大。

GC調優是很重要的。找到最佳的分代堆空間是一個迭代的過程[3,10,12]。這裏咱們假定你已經爲你的應用找到了最佳堆大小。那麼你能夠採用下面的JVM命令來進行設置:

JVM command

 

GC 命令行選項 描述
-Xms 設置Java堆大小的初始值/最小值。例如:-Xms512m (請注意這裏沒有」=」).
-Xmx 設置Java堆大小的最大值
-Xmn 設置年輕代對空間的初始值,最小值和最大值。請注意,年老代堆空間大小是依賴於年輕代堆空間大小的
-XX:PermSize=<n>[g|m|k] 設置持久代堆空間的初始值和最小值
-XX:MaxPermSize=<n>[g|m|k] 設置持久代堆空間的最大值

 

最後一點,最先在Java SE 5.0中有對服務器的人機工程學的介紹[13]。這個能夠很好的減小服務器端應用的調優時間,尤爲是在堆大小測量和複雜GC調優方面。不少狀況下,服務器端調優的最好方式就是不去調優。

 

參考文章

1         Tuning Java Virtual Machines (JVMs)

2        Diagnosing Java.lang.OutOfMemoryError

3        Java Performance by Charlie Hunt and Binu John

4        Java HotSpot VM Options

5        GCViewer (a free open source tool)

6        Comparison Between Sun JDK And Oracle JRockit

7        Java SE 6 Performance White Paper

8       F&Q about Garbage Collection

9        Hotspot Glossary of Terms

10    Memory Management in the Java HotSpot Virtual Machine White Paper

11     Java Hotspot Garbage Collection

12    FAQ about GC in the Hotspot JVM  (with good details)

13    Java Heap Sizing: How do I size my Java heap correctly?

14    Java Tuning White Paper

15     JRockit JVM Heap Size Options

16    Pick up performance with generational garbage collection

17     Which JVM?

18    Memory Management in the Java HotSpot™ Virtual Machine

19    Java Performance Tips

 

英文原文: XML and more,翻譯:ImportNew - 鄭雯

譯文地址: http://www.importnew.com/1551.html

相關文章
相關標籤/搜索