常見OOM問題之PermGen space 永久空間問題詳解

本文來自于HeapDump性能社區(qū)! !有性能問題掠归,上HeapDump性能社區(qū)!

正文:

Java 應用程序只允許使用有限的內存量悄泥。您的特定應用程序可以使用的確切內存量是在應用程序啟動期間指定的虏冻。為了讓事情變得更復雜,Java 內存被分成不同的區(qū)域弹囚,如下圖所示:

v2-acc3571aee7060370c492e0f8d4f69fa_1440w.png

所有這些區(qū)域的大小厨相,包括 permgen 區(qū)域,都是在 JVM 啟動期間設置的鸥鹉。如果您不自己設置大小蛮穿,將使用特定于平臺的默認值。

java.lang.OutOfMemoryError:PermGen space的消息表明永久代的內存區(qū)域被耗盡毁渗。

1践磅,什么原因造成的?

要了解java.lang.OutOfMemoryError: PermGen space 的原因灸异,我們需要了解此特定內存區(qū)域的用途府适。

出于實際目的羔飞,永久代主要由加載并存儲到 PermGen 中的類聲明組成。這包括類的名稱和字段檐春、帶有方法字節(jié)碼的方法逻淌、常量池信息、與類關聯(lián)的對象數(shù)組和類型數(shù)組以及即時編譯器優(yōu)化疟暖。

從上面的定義中卡儒,您可以推斷出永久代的大小要求取決于加載的類的數(shù)量以及此類聲明的大小。因此俐巴,我們可以說*java.lang.OutOfMemoryError: PermGen space 的*****主要原因是加載到永久代的類太多或類太大骨望。

2,舉個例子

如上所述窜骄,永久代空間的使用與加載到 JVM 中的類數(shù)量密切相關锦募。下面的代碼是最直接

導入 javassist.ClassPool; 

public class MicroGenerator { 
  public static void main(String[] args) 拋出異常 { 
    for (int i = 0; i < 100_000_000; i++) { 
      generate("eu.plumbr.demo.Generated" + i); 
    } 
  } 

  public static Class generate(String name) throws Exception { 
    ClassPool pool = ClassPool.getDefault(); 
    返回 pool.makeClass(name).toClass(); 
  } 
}

在這個例子中摆屯,源代碼遍歷一個循環(huán)并在運行時生成類邻遏。javassist庫負責處理類生成的復雜性。

啟動上面的代碼將繼續(xù)生成新類并將它們的定義加載到永久空間中虐骑,直到空間被完全利用并拋出java.lang.OutOfMemoryError: Permgen 空間准验。

重新部署時間示例

對于更復雜和更現(xiàn)實的示例,讓我們帶您了解在應用程序重新部署期間發(fā)生的java.lang.OutOfMemoryError: Permgen space錯誤廷没。當您重新部署應用程序時糊饱,您會期望垃圾回收將擺脫引用所有先前加載的類的先前類加載器,并將其替換為加載類的新版本的類加載器颠黎。

不幸的是另锋,許多 3rd 方庫和對資源(例如線程、JDBC 驅動程序或文件系統(tǒng)句柄)的處理不當使得無法卸載以前使用的類加載器狭归。這反過來意味著在每次重新部署期間夭坪,您的類的所有先前版本仍將駐留在 PermGen 中,在每次重新部署期間生成數(shù)十兆字節(jié)的垃圾过椎。

讓我們想象一個使用 JDBC 驅動程序連接到關系數(shù)據(jù)庫的示例應用程序室梅。當應用程序啟動時,初始化代碼加載 JDBC 驅動程序以連接到數(shù)據(jù)庫疚宇。對應于規(guī)范亡鼠,JDBC 驅動程序使用java.sql.DriverManager注冊自己。此注冊包括在DriverManager的靜態(tài)字段中存儲對驅動程序實例的引用敷待。

現(xiàn)在间涵,當應用程序從應用程序服務器中卸載時,java.sql.DriverManager仍將保留該引用榜揖。我們最終獲得了對驅動程序類的實時引用勾哩,該類又包含對用于加載應用程序的java.lang.Classloader實例的引用股耽。這反過來意味著垃圾收集算法無法回收空間。

并且java.lang.ClassLoader 的那個實例仍然引用應用程序的所有類钳幅,通常在 PermGen 中占用數(shù)十兆字節(jié)物蝙。這意味著只需重新部署幾次即可填充通常大小的 PermGen 并在日志中獲取java.lang.OutOfMemoryError: PermGen space錯誤消息。

3敢艰,解決辦法是什么诬乞?

1.解決初始化時OutOfMemoryError

當應用程序啟動時觸發(fā)由于 PermGen 耗盡導致的 OutOfMemoryError 時,解決方案很簡單钠导。應用程序只需要更多空間將所有類加載到 PermGen 區(qū)域震嫉,所以我們只需要增加它的大小。為此牡属,請更改您的應用程序啟動配置并添加(或增加(如果存在))類似于以下示例的-XX:MaxPermSize參數(shù):

java -XX:MaxPermSize=512m com.yourcompany.YourClass

上述配置將告訴 JVM票堵,允許 PermGen 增長到 512MB,然后才能開始以 OutOfMemoryError 的形式抱怨逮栅。

2.解決重新部署時OutOfMemoryError

當您重新部署應用程序后立即發(fā)生 OutOfMemoryError 時悴势,您的應用程序會遭受類加載器泄漏。在這種情況下措伐,解決問題的最簡單特纤,最直接的方式就是用工具排查,找到有問題的代碼侥加,并解決它以分鐘為單位捧存。

對于那些不能使用 Plumbr 或決定不使用的人,也可以使用替代方法担败。為此昔穴,您應該繼續(xù)進行堆轉儲分析 - 在重新部署后使用類似于以下命令的命令進行堆轉儲:

jmap -dump:format=b,file=dump.hprof <process-id>

然后使用您最喜歡的堆轉儲分析器打開轉儲(Eclipse MAT 是一個很好的工具)。在分析器中提前,您可以查找重復的類吗货,尤其是那些加載應用程序類的類。從那里岖研,您需要進入所有類加載器以找到當前活動的類加載器卿操。

對于不活動的類加載器,您需要通過從不活動的類加載器獲取到GC 根的最短路徑來確定阻止它們被垃圾收集的引用孙援。有了這些信息害淤,您就會找到根本原因。如果根本原因在 3rd 方庫中拓售,您可以繼續(xù)訪問 Google/StackOverflow 以查看這是否是獲取補丁/解決方法的已知問題窥摄。如果這是您自己的代碼,則需要刪除違規(guī)引用础淤。

3.解決運行時OutOfMemoryError

對于那些再次無法使用 Plumbr 的人崭放,也可以使用另一種方法哨苛。在這種情況下,第一步是檢查是否允許 GC 從 PermGen 卸載類币砂。標準的 JVM 在這方面相當保守——類天生就是為了永生建峭。所以一旦加載,即使沒有代碼再使用它們决摧,類也會留在內存中亿蒸。當應用程序動態(tài)創(chuàng)建大量類并且長時間不需要生成的類時,這可能會成為一個問題掌桩。在這種情況下边锁,允許 JVM 卸載類定義會很有幫助。這可以通過向啟動腳本添加一個配置參數(shù)來實現(xiàn):

-XX:+CMSClassUnloadingEnabled

默認情況下波岛,它設置為 false茅坛,因此要啟用它,您需要在 Java 選項中顯式設置以下選項则拷。如果您啟用CMSClassUnloadingEnabled贡蓖,GC 也會清除PermGen 并刪除不再使用的類。請記住隔躲,此選項僅在使用以下選項啟用UseConcMarkSweepGC時才有效摩梧。因此物延,當運行ParallelGC或宣旱,上帝保佑,Serial GC 時叛薯,請確保您已通過指定將 GC 設置為CMS

-XX:+UseConcMarkSweepGC

在確被胍鳎可以卸載類并且問題仍然存在后,您應該繼續(xù)進行堆轉儲分析 - 使用類似于以下的命令進行堆轉儲:

jmap -dump:file=dump.hprof,format=b <process-id>

然后使用您最喜歡的堆轉儲分析器(例如 Eclipse MAT)打開轉儲耗溜,并根據(jù)加載的類數(shù)量繼續(xù)查找最昂貴的類加載器组力。從這樣的類加載器中,您可以繼續(xù)提取加載的類并按實例對此類類進行排序抖拴,以獲得可疑的頂部列表燎字。

對于每個嫌疑人,您需要手動將根本原因追溯到生成此類類的應用程序代碼阿宅。

Java OOM系列專題:

第一篇:Java OOM 原理篇 : 什么是 Java OOM

第二篇:Java OOM 基礎篇:常見的OutOfMemoryError 場景一:Java heap space 堆溢出問題詳解

第三篇:Java OOM 基礎篇:常見的OutOfMemoryError 場景二 : GC overhead limit exceeded 問題詳解

第四篇:Java OOM 基礎篇:常見的OutOfMemoryError 場景三: PermGen space 永久空間問題詳解

第五篇:Java OOM 基礎篇:常見的OutOfMemoryError 場景四: Permgen size 元空間問題詳解

第六篇:Java OOM 實戰(zhàn)篇:應用故障之Java heap space 堆溢出實戰(zhàn)

第七篇:Java OOM 高級篇:體驗了一把線上CPU100%及應用OOM的排查和解決過程

第八篇:Java OOM 高級篇:線上Docker 上Springboot程序OOM問題的排查分享

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末候衍,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子洒放,更是在濱河造成了極大的恐慌蛉鹿,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件往湿,死亡現(xiàn)場離奇詭異妖异,居然都是意外死亡惋戏,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門他膳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來响逢,“玉大人,你說我怎么就攤上這事棕孙×渚洌” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵散罕,是天一觀的道長分歇。 經常有香客問我,道長欧漱,這世上最難降的妖魔是什么职抡? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮误甚,結果婚禮上缚甩,老公的妹妹穿的比我還像新娘。我一直安慰自己窑邦,他們只是感情好擅威,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著冈钦,像睡著了一般郊丛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瞧筛,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天厉熟,我揣著相機與錄音,去河邊找鬼较幌。 笑死揍瑟,一個胖子當著我的面吹牛,可吹牛的內容都是我干的乍炉。 我是一名探鬼主播绢片,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼岛琼!你這毒婦竟也來了底循?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤衷恭,失蹤者是張志新(化名)和其女友劉穎此叠,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡灭袁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年猬错,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茸歧。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡倦炒,死狀恐怖,靈堂內的尸體忽然破棺而出软瞎,到底是詐尸還是另有隱情逢唤,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布涤浇,位于F島的核電站鳖藕,受9級特大地震影響,放射性物質發(fā)生泄漏只锭。R本人自食惡果不足惜著恩,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蜻展。 院中可真熱鬧喉誊,春花似錦、人聲如沸纵顾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽施逾。三九已至敷矫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間音念,已是汗流浹背沪饺。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留闷愤,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓件余,卻偏偏與公主長得像讥脐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子啼器,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內容