本文由 ImportNew - Peter Pan 翻譯自 javacodegeeks。如需轉載本文,請先參見文章末尾處的轉載要求。
html
ImportNew注:若是你也對Java技術翻譯分享感興趣,歡迎加入咱們的 Java開發 小組。參與方式請查看小組簡介。 java
垃圾回收是Java開發人員理解得最不完全的地方之一。他們以爲既然JVM負責垃圾回收,那麼便沒必要擔憂內存的分配跟回收等問題。可是當應用變得複雜的時候,垃圾回收一樣變得複雜起來,並且一旦垃圾回收變得複雜,程序的性能就會受到影響。因此,這篇文章將會幫助Java開發人員更好地理解垃圾回收機制是怎樣工做的,以及如何修復Java中的「Out of Memory」問題。有兩個十分廣泛的致使「Out of Memory」問題的因素。第一個是堆大小,第二個就是PermGen Space。 apache
永久代和類加載器 數組
Java對象是Java類的實例。每一次建立一個新的Java對象,JVM就會建立一個該對象的內部標識並把該對象存儲在堆中。若是是首次訪問該類,JVM就必須加載它。類加載是定位相關類文件、在硬盤上找到該文件、加載該文件並解析文件結構的一系列過程。確保類的正確加載是類加載器(ClassLoader)的責任。一個Java程序中的每個類都必須被相同的類加載器加載。類加載器是java.lang.ClassLoader類的實例。類加載器把Java類暫時加載到Perm Space中。 tomcat
JVM也建立了Java類的內部標識並把java類存儲在永久代中。在垃圾回收期間,對象跟類都被看做對象且用相同的方式進行垃圾回收。最初,類和對象都被存儲在堆空間。 服務器
做爲優化性能,會建立永久代並將被放在永久代中。類是咱們的JVM實現的一部分,而且咱們不該該用數據結構填滿Java堆。永久代內存分配在堆以外,包含如下類的信息: 數據結構
類的方法 框架
類的名字 性能
常量池信息 優化
跟類有關的對象數組和類型數組
JVM使用的內部對象
編譯器優化的使用信息
既然如今咱們已經理解了永久代是什麼,那麼就讓咱們看一看是什麼引起了內存問題。
PermGen Space
當JVM須要加載一個新類的定義的卻發如今PermGen沒有足夠的空間時,」java.lang.OutOfMemoryError: PermGen Space」錯誤便發生了。默認分配的永久代內存空間(PermGen Space),服務器模式是64M,客戶端模式是32M。有兩個可能緣由致使永久代內存空間問題。
第一個緣由多是你的應用程序或服務器擁有太多的類,而已有永久代內存空間不足以容納全部的類。
-XX:MaxPermSize=XXXM
若是出現OOM,這是由於類太多而引發的永久代內存空間不足,那麼你能夠經過增長 +XX:MaxPermGenSize=XXXM 大小的方式來增長永久代的內存空間。這樣作會加大存儲類的空間變量的大小,而且 +XX:MaxPermGenSize 參數應該設置爲256M。
-XX:+CMSClassUnloadingEnabled
這個參數顯示在使用CMS GC時,未加載類是否可用。該參數默認值爲false,由此,你須要在java選項中顯示設置下面選項:
1
|
-XX:+CMSClassUnloadingEnabled
|
若是你啓用 CMSClassUnloadingEnabled ,JVM進行GC時便會清除永久代,而且刪除再也不使用的類。這個選項只會在 UseConcMarkSweepGC 可用時才起做用。經過如下選項使 UseConcMarkSweepGC 可用:
1
|
-XX:+ UseConcMarkSweepGC
|
-XX:+CMSPermGenSweepingEnabled
這個參數顯示清除永久代是否可用。默認狀況下這個參數是不可用的,因此要協調永久代問題,就必須顯示設置這個參數。這個參數在Java 6裏面被刪除,因此若是你在使用Java 6或以上版本,你將不得不使用 -XX:+CMSClassUnloadingEnabled 選項。因此,爲了解決永久代空間的內存問題,被添加的選項看起來以下:
1
|
-XX:MaxPermSize=128M –XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled
|
內存泄漏
第二個緣由多是內存泄露。被加載的類定義如何變成沒有被使用?
正常狀況下,在Java中類是永久存在的。因此一旦類被加載,他們將一直停留在內存中,即使其所在應用服務器端已經中止運行。像cglib這樣的動態類產生庫,在他們動態建立了大量類以後,會使用大量永久代內存空間。在運行時建立的代理類被普遍地使用。當單個類定義被用於產生多個實例時,建立新的代理類將會很容易。
Spring和Hibernate常常產生某個類的代理,這些代理類被類加載器加載。產生的類定義從不被清理,致使永久性堆空間迅速填滿。
爲了解決永久代內存空間問題,你須要識別出泄露的緣由並修補它。增大永久代內容空間不會有益於解決卻只會延緩這類問題,由於在某種意義上,永久代內存空間終將被填滿。
若是你正在使用Tomcat且常常遇到內存溢出問題,最新版本的Tomcat已經有足夠的容量來解決某些內存溢出問題。
總結
一旦你遇到永久代內存空間問題,你須要找出這個問題是不是因爲你的應用程序加載了大量的類或出現了內存泄露。若是是因爲類太多,精確地協調分配永久代內存空間可以解決。若是是因爲內存泄露,你須要找到泄露的根本緣由並標記出來。像cglib、Spring、Hibernate這樣的框架會動態生成大量的類,因此在使用這些框架時分配更多的永久代內存空間是更好的選擇。
原文連接: javacodegeeks 翻譯: ImportNew.com - Peter Pan
譯文連接: http://www.importnew.com/8133.html