現(xiàn)在,網(wǎng)上關(guān)于討論P(yáng)ermGen OOM的資料很多,但是深入分析PermGen區(qū)域內(nèi)存溢出原因的資料很少。本篇文章嘗試全面分析一下PermGen OOM的原因,其中涉及到了Java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)、類(lèi)型裝載、類(lèi)型卸載等,測(cè)試代碼涉及到了JMX協(xié)議。相關(guān)前提知識(shí)如下:
1、Java類(lèi)加載的基本原理
2、Java類(lèi)型卸載相關(guān)的知識(shí),
http://m.tkk7.com/zhuxing/archive/2008/07/24/217285.html
3、簡(jiǎn)要了解JMX協(xié)議,有關(guān)JMX協(xié)議可以參加sun公司發(fā)布的技術(shù)規(guī)范,對(duì)JMX協(xié)議做一定的了解對(duì)理解Java性能監(jiān)控和調(diào)優(yōu)功能的實(shí)現(xiàn)原理有很大幫助。
【虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)介紹】
本部分將對(duì)Java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)做一個(gè)簡(jiǎn)單的介紹,著重說(shuō)明PermGen區(qū)域(永久存儲(chǔ)區(qū))存放的內(nèi)容,并對(duì)運(yùn)行時(shí)數(shù)據(jù)區(qū)的訪問(wèn)方式做一個(gè)歸納說(shuō)明,為后面深入分析類(lèi)型卸載和PermGen OOM做鋪墊。為了更具有通用性,本部分將更多關(guān)注虛擬機(jī)協(xié)議本身,可能和具體的虛擬機(jī)實(shí)現(xiàn)有少許的出入。
【運(yùn)行時(shí)數(shù)據(jù)區(qū)分類(lèi)】
Java虛擬機(jī)的運(yùn)行時(shí)數(shù)據(jù)區(qū)一般分類(lèi)如下(不一定是物理劃分):
堆:主要存放對(duì)象實(shí)例,線程共享
棧:主要存儲(chǔ)特定線程的方法調(diào)用狀態(tài),線程獨(dú)占
本地方法棧:存儲(chǔ)本地方法的調(diào)用狀態(tài),線程獨(dú)占
PC寄存器:學(xué)過(guò)操作系統(tǒng)課程的都知道,線程獨(dú)占
方法區(qū):主要存儲(chǔ)了類(lèi)型信息,線程共享
方法區(qū)可以簡(jiǎn)單的等價(jià)為所謂的PermGen區(qū)域(永久存儲(chǔ)區(qū)),在很多虛擬機(jī)相關(guān)的文檔中,也將其稱(chēng)之為"永久堆"(permanent heap),作為堆空間的一部分存在。介于此,我們可以簡(jiǎn)單說(shuō)明一下我們常用的幾個(gè)堆內(nèi)存配置的參數(shù)關(guān)系:
*-XX: PermSize:*永久堆(Pergen區(qū)域)大小默認(rèn)值
*-XX:MaxPermSize:*永久堆(Pergen區(qū)域)最大值
*-Xms:*堆內(nèi)存大小默認(rèn)值
*-Xmx:*堆內(nèi)存最大值
【運(yùn)行時(shí)數(shù)據(jù)區(qū)訪問(wèn)方式總結(jié)】
從開(kāi)發(fā)者角度,虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的訪問(wèn)方式簡(jiǎn)要?dú)w納如下:
活動(dòng)的線程可以通過(guò)對(duì)應(yīng)的棧來(lái)訪問(wèn)運(yùn)行時(shí)數(shù)據(jù)區(qū)信息
棧是堆訪問(wèn)的入口
堆上Java.lang.Class實(shí)例是訪問(wèn)PermGen區(qū)域中類(lèi)型信息的入口
- 一個(gè)類(lèi)型裝載之后會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)的java.lang.Class實(shí)例,這個(gè)實(shí)例本身和普通對(duì)象實(shí)例一樣存儲(chǔ)于堆中,我覺(jué)得之所以說(shuō)是這是一種特殊的實(shí)例,某種程度上是因?yàn)槠涑洚?dāng)了訪問(wèn)PermGen區(qū)域中類(lèi)型信息的代理者。
- 圖中"Class類(lèi)型實(shí)例"和"類(lèi)加載器實(shí)例"分別是A類(lèi)型對(duì)應(yīng)的java.lang.Class實(shí)例和加載A類(lèi)型的類(lèi)加載器實(shí)例。
- 只要是有active的對(duì)象實(shí)例句柄,就能夠訪問(wèn)到對(duì)應(yīng)的Class類(lèi)型實(shí)例和類(lèi)加載器實(shí)例,分別通過(guò)Object.getClass()方法和Class.getClassLoader()方法。
- 只要是有active的Class類(lèi)型實(shí)例句柄,就能夠訪問(wèn)到對(duì)應(yīng)的類(lèi)加載器實(shí)例。
【PermGen內(nèi)存溢出深入分析】
【前提知識(shí)】
由不同的類(lèi)加載器實(shí)例加載的類(lèi)型可以等價(jià)為完全不同的類(lèi)型,哪怕時(shí)同一類(lèi)型類(lèi)加載器的不同實(shí)例加載的,都會(huì)在PermGen區(qū)域分配相應(yīng)的空間來(lái)存儲(chǔ)類(lèi)型信息
新類(lèi)型加載時(shí),會(huì)在PermGen區(qū)域申請(qǐng)相應(yīng)的空間來(lái)存儲(chǔ)類(lèi)型信息,類(lèi)型被卸載后,PermGen區(qū)域上的垃圾收集會(huì)釋放對(duì)應(yīng)的內(nèi)存空間。PermGen區(qū)域和普通的堆空間一樣,也遵循垃圾收集的規(guī)律,所以,網(wǎng)上很多資料種關(guān)于PermGen區(qū)域空間的大小是只增不減的說(shuō)法是不正確的,后面會(huì)用相應(yīng)的測(cè)試代碼來(lái)驗(yàn)證和分析。
一種類(lèi)型被卸載的前提條件是:加載此類(lèi)型的類(lèi)加載器實(shí)例變?yōu)椴豢蛇_(dá)(unreachable)狀態(tài),虛擬機(jī)協(xié)議中對(duì)應(yīng)描述如下:
A class or interface may be unloaded if and only if its class loader is unreachable. The bootstrap class loader is always reachable; as a result, system classes may never be unloaded.
關(guān)于實(shí)例的*unreachable*狀態(tài),大致可以理解為不能通過(guò)特定活動(dòng)線程對(duì)應(yīng)的棧出發(fā)通過(guò)引用計(jì)算來(lái)到達(dá)對(duì)應(yīng)的實(shí)例,虛擬機(jī)協(xié)議中對(duì)應(yīng)描述如下:
_A reachable object is any object that can be accessed in any potential continuing
computation from any live thread._
結(jié)合上面的[虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的介紹|],可以得出結(jié)論:類(lèi)型對(duì)應(yīng)的普通實(shí)例、類(lèi)型對(duì)應(yīng)的java.lang.Class實(shí)例、加載此類(lèi)型的ClassLoader實(shí)例,三者中有任何一種或者多種是reachable狀態(tài)的,那么此類(lèi)型就不可能被卸載。
JMX協(xié)議提供了相應(yīng)的API接口,用來(lái)在運(yùn)行時(shí)查詢(xún)當(dāng)前虛擬機(jī)實(shí)例的內(nèi)存使用和類(lèi)型加載等信息。這也是很多Java性能監(jiān)控和分析工具的基礎(chǔ),后面的測(cè)試程序中也有相應(yīng)的代碼使用了JMX協(xié)議。
【測(cè)試程序分析】
虛擬機(jī)器參數(shù)設(shè)置如下:
-XX: PermSize=4M -XX:MaxPermSize=4M -verbose -verbose:gc
設(shè)置-verbose參數(shù)是為了獲取類(lèi)型加載和卸載的信息
設(shè)置-verbose:gc是為了獲取垃圾收集的相關(guān)信息
在D:/classes目錄下有一個(gè)簡(jiǎn)單的類(lèi)型ZhuXing對(duì)應(yīng)的class字節(jié)碼,測(cè)試代碼中用URLClassLoader來(lái)加載此類(lèi)型
【測(cè)試程序一:模擬PermGen OOM】
1 try {
2 //準(zhǔn)備url
3 URL url = new File("D:/classes").toURL();
4 URL[] urls = {url};
5
6 //獲取有關(guān)類(lèi)型加載的JMX接口
7 ClassLoadingMXBean loadingBean = ManagementFactory.getClassLoadingMXBean();
8
9 //用于緩存類(lèi)加載器
10 List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
11
12 while (true) {
13 //加載類(lèi)型并緩存類(lèi)加載器實(shí)例
14 ClassLoader classLoader = new URLClassLoader(urls);
15 classLoaders.add(classLoader);
16 classLoader.loadClass("ZhuXing");
17
18 //顯示數(shù)量信息(共加載過(guò)的類(lèi)型數(shù)目,當(dāng)前還有效的類(lèi)型數(shù)目,已經(jīng)被卸載的類(lèi)型數(shù)目)
19 System.out.println("total: " + loadingBean.getTotalLoadedClassCount());
20 System.out.println("active: " + loadingBean.getLoadedClassCount());
21 System.out.println("unloaded: " + loadingBean.getUnloadedClassCount());
22 }
23 } catch (Exception e) {
24 e.printStackTrace();
25 }
26
27
【測(cè)試程序一分析】
運(yùn)行測(cè)試程序一,輸出信息如下(摘取了部分):
......
[Loaded ZhuXing from [file:/D:/classes/]]
total: 2914
active: 2914
unloaded: 0
[Loaded ZhuXing from [file:/D:/classes/]]
total: 2915
active: 2915
unloaded: 0
[Full GC 4852K->4852K(8720K), 0.0993780 secs]
[Full GC 4852K->4829K(8720K), 0.0999775 secs]
[Full GC 4829K->4829K(8720K), 0.0989805 secs]
[Full GC 4829K->4829K(8720K), 0.0997261 secs]
......
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
......
[Unloading class ZhuXing]
......
[Loaded java.lang.Shutdown from D:\eos6\jdk1.5.0_09\jre\lib\rt.jar]
[Loadedjava.lang.Shutdown$Lockfrom D:\eos6\jdk1.5.0_09\jre\lib\rt.jar
針對(duì)以上摘錄的虛擬機(jī)器運(yùn)行時(shí)信息,分析結(jié)論如下:
一直在持續(xù)的加載類(lèi)型ZhuXing,而且一直沒(méi)有卸載,直到PermGen OOM發(fā)生。類(lèi)型ZhuXing無(wú)法卸載的原因,前面說(shuō)明過(guò),是由于對(duì)應(yīng)的類(lèi)加載器實(shí)例一直是reachaable狀態(tài),緩存對(duì)象實(shí)例或者java.lang.Class實(shí)例同樣可以達(dá)到無(wú)法卸載類(lèi)型的效果。
在PermGen OOM發(fā)生前,虛擬機(jī)進(jìn)行了非常頻繁的垃圾收集,效果甚微
在PermGen OOM發(fā)生后,卸載了類(lèi)型ZhuXing,當(dāng)前虛擬機(jī)實(shí)例退出
【測(cè)試程序二:PermGen區(qū)域垃圾收集】
和測(cè)試程序一相比,刪除了類(lèi)加載器實(shí)例緩存的代碼。
1 try {
2 //準(zhǔn)備url
3 URL url = new File("D:/classes").toURL();
4 URL[] urls = {url};
5
6 //獲取有關(guān)類(lèi)型加載的JMX接口
7 ClassLoadingMXBean loadingBean = ManagementFactory.getClassLoadingMXBean();
8
9 while (true) {
10 //加載類(lèi)型,不緩存類(lèi)加載器實(shí)例
11 new URLClassLoader(urls).loadClass("ZhuXing");
12 //顯示數(shù)量信息(共加載過(guò)的類(lèi)型數(shù)目,當(dāng)前還有效的類(lèi)型數(shù)目,已經(jīng)被卸載的類(lèi)型數(shù)目)
13 System.out.println("total: " + loadingBean.getTotalLoadedClassCount());
14 System.out.println("active: " + loadingBean.getLoadedClassCount());
15 System.out.println("unloaded: " + loadingBean.getUnloadedClassCount());
16 }
17 } catch (Exception e) {
18 e.printStackTrace();
19 }
20
21
【測(cè)試程序二分析】
運(yùn)行測(cè)試程序二很長(zhǎng)時(shí)間,一直沒(méi)有發(fā)生PermGen OOM異常,輸出信息如下(摘取了部分):
...
[Loaded ZhuXing from [file:/D:/classes/]]
total: 19540
active: 1052
unloaded: 18488
[Full GC 1563K->259K(2112K), 0.1758958 secs]
......
[Unloading class ZhuXing]
[Unloading class ZhuXing]
[Unloading class ZhuXing]
......
[GC 1968K->1563K(2112K), 0.0025266 secs]
......
[Loaded ZhuXing from [file:/D:/classes/]]
total: 21098
active: 440
unloaded: 20658
...
針對(duì)以上摘錄的虛擬機(jī)器運(yùn)行時(shí)信息,分析結(jié)論如下:
- 類(lèi)型ZhuXing在頻繁被加載的同時(shí),也在頻繁被卸載,當(dāng)被加載的類(lèi)型達(dá)到了21098時(shí),并沒(méi)有發(fā)生PermGen OOM,20658已經(jīng)被卸載,堆內(nèi)存的占用比測(cè)試代碼一中小的多
- 中間進(jìn)行的垃圾并不是特別頻繁,但是垃圾收集的效果較為明顯
- 類(lèi)型被卸載之后,伴隨著PermGen區(qū)域上的垃圾收集和新類(lèi)型的不斷被加載,PermGen區(qū)域中類(lèi)型信息占有的堆內(nèi)存大小在有序的增大減小
【PermGen OOM原因總結(jié)】
通過(guò)上面的[測(cè)試程序分析|],我們發(fā)現(xiàn)PermGen OOM發(fā)生的原因和類(lèi)型裝載、類(lèi)型卸載有直接的關(guān)系,可以對(duì)PermGen OOM發(fā)生的原因做如下大致的總結(jié):
1、PermGen區(qū)域分配的堆空間過(guò)小,可以通過(guò)設(shè)置-XX: PermSize參數(shù)和-XX:MaxPermSize參數(shù)來(lái)解決。
2、類(lèi)型卸載不及時(shí),過(guò)時(shí)無(wú)效的類(lèi)型信息占用了空間,我們不妨稱(chēng)其為"永久堆"的內(nèi)存泄漏,需要通過(guò)深入分析類(lèi)型卸載的原理來(lái)尋找對(duì)應(yīng)的防范措施
【常見(jiàn)的類(lèi)加載器和類(lèi)型卸載的可能性總結(jié)】
通過(guò)前面的討論,我們知道如果加載某種類(lèi)型的類(lèi)加載器實(shí)例沒(méi)有處于unreachable狀態(tài),則該類(lèi)型就不會(huì)被卸載,該類(lèi)型不被卸載,則對(duì)應(yīng)的類(lèi)型信息在PermGen區(qū)域中占有的堆內(nèi)存就不會(huì)被釋放。下面,針對(duì)典型的Java應(yīng)用分類(lèi),分析一下常用類(lèi)加載器加載的類(lèi)型被下載的可能性。
【普通Java應(yīng)用】
啟動(dòng)類(lèi)加載器:由于其負(fù)責(zé)加載虛擬機(jī)的核心類(lèi)型,所以由其加載的類(lèi)型在整個(gè)程序運(yùn)行期間不可能被卸載,對(duì)應(yīng)類(lèi)型信息占用的PermGen區(qū)域堆空間不可能得到釋放。
擴(kuò)展類(lèi)加載器:負(fù)責(zé)加載JDK擴(kuò)展路徑下的類(lèi)型,擴(kuò)展類(lèi)加載器同時(shí)又作為系統(tǒng)類(lèi)加載器的父類(lèi)加載器,所以,由其加載的類(lèi)型在整個(gè)程序運(yùn)行期間基本上不可能被卸載,對(duì)應(yīng)類(lèi)型信息占用的PermGen區(qū)域堆空間基本不可能得到釋放。
系統(tǒng)類(lèi)加載器:負(fù)責(zé)加載程序類(lèi)路徑上面的類(lèi)型,由其加載的類(lèi)型在整個(gè)程序運(yùn)行期間基本上不可能被卸載,對(duì)應(yīng)類(lèi)型信息占用的PermGen區(qū)域堆空間基本不可能得到釋放。
用戶(hù)自定義類(lèi)加載器:對(duì)于其加載的類(lèi)型,滿(mǎn)足類(lèi)型卸載要求的可能性比較容易控制,只要是其實(shí)例本身處于unreachable狀態(tài),其加載的類(lèi)型會(huì)被卸載,PermGen區(qū)域中對(duì)應(yīng)的空間占有也會(huì)被釋放。
【插件開(kāi)發(fā)】
系統(tǒng)類(lèi)加載器:由于其負(fù)責(zé)加載虛擬機(jī)的核心類(lèi)型,所以由其加載的類(lèi)型在插件應(yīng)用運(yùn)行期間不可能被卸載,對(duì)應(yīng)類(lèi)型信息占用的PermGen區(qū)域堆空間不可能得到釋放。
插件類(lèi)加載器:系統(tǒng)插件類(lèi)加載器負(fù)責(zé)加載OSGI實(shí)現(xiàn)的相關(guān)類(lèi)型,所以由其加載的類(lèi)型在插件應(yīng)用運(yùn)行期間不可能被卸載;用戶(hù)開(kāi)發(fā)的插件所使用的默認(rèn)插件類(lèi)加載器,和特定的插件本身進(jìn)行域綁定,插件之間存在一定的類(lèi)型引用關(guān)系,并且特定插件在整個(gè)插件應(yīng)用的運(yùn)行時(shí)被停止的可能性也很小,所以類(lèi)型卸載發(fā)生幾率極小。
用戶(hù)自定義類(lèi)加載器:對(duì)于其加載的類(lèi)型,滿(mǎn)足類(lèi)型卸載要求的可能性比較容易控制,只要是其實(shí)例本身處于unreachable狀態(tài),其加載的類(lèi)型會(huì)被卸載,PermGen區(qū)域中對(duì)應(yīng)的空間占有也會(huì)被釋放。
【PermGen內(nèi)存溢出的應(yīng)對(duì)措施】
通過(guò)上面的PermGen OOM的原因的分析,不難看出對(duì)應(yīng)的應(yīng)對(duì)措施:
合理的設(shè)置-XX: PermSize和-XX:MaxPermSize參數(shù)(主要的有效措施)
有效的利用的虛擬機(jī)類(lèi)型卸載的機(jī)制(針對(duì)程序進(jìn)行調(diào)優(yōu))
【合理設(shè)置參數(shù)(針對(duì)普通用戶(hù)和開(kāi)發(fā)者)】
通過(guò)設(shè)置合理的XX: PermSize和-XX:MaxPermSize參數(shù)值是減少和有效避免PermGen OOM發(fā)生的最有效最主要的措施,尤其是針對(duì)普通用戶(hù)而言,這基本上是唯一的辦法。關(guān)于合理設(shè)置這兩個(gè)參數(shù),建議如下:
XX: PermSize參數(shù)的設(shè)置盡量建立在基準(zhǔn)測(cè)試的基礎(chǔ)之上,可以利用監(jiān)控工具對(duì)穩(wěn)定運(yùn)行期間PermGen區(qū)域的大小進(jìn)行統(tǒng)計(jì),取合理的平均值。網(wǎng)上的很多資料中,建議XX: PermSize和XX:MaxPermSize設(shè)置為相同的數(shù)值,個(gè)人覺(jué)得這是不正確的,因?yàn)閮蓚€(gè)參數(shù)的出發(fā)點(diǎn)是不一樣的。XX: PermSize設(shè)置的過(guò)大肯定會(huì)在應(yīng)用運(yùn)行的大部分時(shí)間中浪費(fèi)堆內(nèi)存,有可能會(huì)明顯增加存放普通對(duì)象實(shí)例的堆空間的垃圾收集的次數(shù)。
XX:MaxPermSize參數(shù)的設(shè)置應(yīng)該著眼于PermGen區(qū)域使用的峰值,因?yàn)檫@是避免PermGen OOM的最后一道屏障,其設(shè)置最好也是建立在性能監(jiān)控工具的統(tǒng)計(jì)結(jié)果之上。
和虛擬機(jī)有關(guān)的性能參數(shù)較多的分為兩類(lèi),一類(lèi)是初始值或默認(rèn)值,一類(lèi)是峰值。如果該性能參數(shù)是會(huì)涉及到的虛擬機(jī)垃圾收集機(jī)制的,關(guān)于初始值或者默認(rèn)值的設(shè)置盡量要建立在測(cè)試基礎(chǔ)之上,盡量做到在單次垃圾收集時(shí)間和垃圾收集頻率之間保持一個(gè)平衡,否則很有可能適得其反。
【有效利用虛擬機(jī)類(lèi)型卸載機(jī)制(針對(duì)開(kāi)發(fā)者)】
此部分的建議可以作為開(kāi)發(fā)者進(jìn)行性能調(diào)優(yōu)或者日常開(kāi)發(fā)時(shí)候的參考,盡量能夠配合相應(yīng)的性能監(jiān)控工具進(jìn)行:
檢查是否由于程序設(shè)計(jì)本身上的缺陷,導(dǎo)致加載了大量實(shí)際上并不需要的類(lèi)型。較新版本的Java虛擬機(jī)實(shí)現(xiàn),一般都遵循動(dòng)態(tài)解析的建議,所以不是人為設(shè)計(jì)的缺陷,一般不會(huì)誘發(fā)加載了大量實(shí)際上并不需要的類(lèi)型。結(jié)合插件開(kāi)發(fā)的應(yīng)用場(chǎng)景,個(gè)人覺(jué)得插件功能模塊的劃分(其中包括了插件依賴(lài)關(guān)系的設(shè)計(jì)和有關(guān)擴(kuò)展點(diǎn)的擴(kuò)展收集等)和第三方j(luò)ar的使用可能是誘發(fā)此問(wèn)題的兩個(gè)重要根源。
對(duì)象緩存的使用是否得當(dāng),通過(guò)前面的分析,我們知道這可能是導(dǎo)致類(lèi)型不能被卸載的重要原因。緩存的使用,既要認(rèn)識(shí)到其可以提高時(shí)間性能的有點(diǎn),也要分析其可能會(huì)給普通對(duì)象堆空間和PermGen區(qū)域造成的負(fù)擔(dān)。
自定義類(lèi)加載器的合理使用,相關(guān)的幾個(gè)注意要點(diǎn)包括:
- 是否不恰當(dāng)?shù)睦玫念?lèi)型更新的特性,也就是說(shuō)是否對(duì)類(lèi)加載器實(shí)例的unreachable狀態(tài)做了有效的判斷。考慮如下場(chǎng)景,假設(shè)用戶(hù)開(kāi)發(fā)了一個(gè)自定義類(lèi)加載器來(lái)加載工程輸出目錄下的臨時(shí)類(lèi)型,對(duì)臨時(shí)類(lèi)型做了不必要的緩存,這肯定會(huì)導(dǎo)致所有被加載過(guò)的臨時(shí)類(lèi)型都不會(huì)得到卸載,會(huì)直接加重PermGen區(qū)域的負(fù)擔(dān)。
- 自定義類(lèi)加載器和其他已有類(lèi)加載器的協(xié)作關(guān)系是否合理,是否合理的利用了Java類(lèi)加載的雙親委派機(jī)制。我們知道,不同的類(lèi)加載器實(shí)例(哪怕是同一種類(lèi)加載器類(lèi)型的不同實(shí)例)加載的同一種自定義類(lèi)型在虛擬機(jī)內(nèi)部都會(huì)被放置到不同的命名空間中作為不同類(lèi)型來(lái)處理,所以合理的設(shè)置父類(lèi)加載器變得很重要,不合理的設(shè)置會(huì)導(dǎo)致大量不必要的"新"類(lèi)型被創(chuàng)造出來(lái),況且這些不必要的"新"類(lèi)型是否能夠被及時(shí)卸載還是個(gè)未知數(shù)。
慎重檢查自定義類(lèi)加載器實(shí)例是否被不恰當(dāng)?shù)木彺媪耍虿谎远鳌?
【后記】
寫(xiě)這篇文章的初衷是為了深入的分析PermGen OOM發(fā)生的原因,在深入分析的基礎(chǔ)之上理解PermGen OOM的應(yīng)對(duì)措施,從"為什么會(huì)發(fā)生PermGen OOM"到"到底為什么會(huì)發(fā)生PermGen OOM"。希望對(duì)大家更深入的認(rèn)識(shí)PermGen OOM和PermGen OOM的應(yīng)對(duì)措施起到作用,謝謝!
本博客中的所有文章、隨筆除了標(biāo)題中含有引用或者轉(zhuǎn)載字樣的,其他均為原創(chuàng)。轉(zhuǎn)載請(qǐng)注明出處,謝謝!