新聞中心
似乎從 Java 入門(mén)的時(shí)候,就有這樣的說(shuō)法來(lái)考查 Java開(kāi)發(fā)者:

創(chuàng)新互聯(lián)建站是一家集網(wǎng)站建設(shè),嵐皋企業(yè)網(wǎng)站建設(shè),嵐皋品牌網(wǎng)站建設(shè),網(wǎng)站定制,嵐皋網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷,網(wǎng)絡(luò)優(yōu)化,嵐皋網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力。可充分滿足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
| Java 不像 C++ 那樣自己管理內(nèi)存,有Java 虛擬機(jī)負(fù)責(zé)進(jìn)行垃圾回收,再也沒(méi)有內(nèi)存泄露的問(wèn)題了。 |
但是隨著開(kāi)發(fā)經(jīng)歷的增長(zhǎng),已經(jīng)開(kāi)發(fā)過(guò)應(yīng)用的增多,應(yīng)用內(nèi)需要加載的 class 增多,經(jīng)常就會(huì)遇到內(nèi)存溢出(OOM)。或者更確切的說(shuō),因?yàn)榧虞d class 的增多導(dǎo)致的內(nèi)存溢出是
- java.lang.OutOfMemoryError: PermGen space
此時(shí),解決OOM的方式一般是:
1. 分析應(yīng)用的代碼寫(xiě)的是否有問(wèn)題,可以通過(guò)一些工具觀察應(yīng)用內(nèi)占用內(nèi)存較多的 class 類型 (比如通過(guò) JVisualVM 來(lái)分析Java七武器系列多情環(huán) --多功能Profiling工具 JVisual VM,或者通過(guò)MAT來(lái)分析)
2. 修改 JVM啟動(dòng)參數(shù),增大關(guān)于 Perm Gen 的配置。
在 Tomcat 這一類的 應(yīng)用服務(wù)器中,由于其做為應(yīng)用的容器運(yùn)行,可能自身的Perm Gen 占用并不多,但需要考慮部署到容器中的應(yīng)用占用。有些應(yīng)用依賴了大量的第三方類庫(kù),也有一些應(yīng)用會(huì)在運(yùn)行時(shí)動(dòng)態(tài)生成大量的 class,這些內(nèi)容的加載,都容易導(dǎo)致 Perm Gen 的 OOM。
對(duì)于 OOM 的處理,內(nèi)部會(huì)在啟動(dòng)時(shí)占用一小塊內(nèi)存,在 OOM 產(chǎn)生的時(shí)候釋放掉來(lái)臨時(shí)緩解一下,這種稱為oomParachute。
除此之外,Tomcat 在 manager 應(yīng)用中還提供了發(fā)現(xiàn)內(nèi)存泄漏的功能。
圖上說(shuō)明寫(xiě)的明白,該功能主要用于分析在應(yīng)用停止、重部署、解除部署時(shí)是否造成了內(nèi)存泄漏。
在請(qǐng)求后,manager的上方信息顯示區(qū)域會(huì)提示當(dāng)前是否有應(yīng)用造成的內(nèi)存泄漏。
但需要注意的是此功能會(huì)觸發(fā)一次 Full GC 的執(zhí)行,代碼中使用的是 System.gc(),在生產(chǎn)環(huán)境中如果使用需要謹(jǐn)慎。
那么,在什么情況下會(huì)導(dǎo)致所謂的應(yīng)用內(nèi)存泄漏呢?
我們都知道, 為了實(shí)現(xiàn)應(yīng)用間的 class 隔離, Tomcat 對(duì)于每個(gè)應(yīng)用,都會(huì)單獨(dú)使用一個(gè) WebappClassLoader,這樣,多個(gè)應(yīng)用間即使都使用到一個(gè) 類庫(kù)的不同版本,也不會(huì)相互影響造成沖突。
但是,在這種情況下,當(dāng)一個(gè)應(yīng)用已經(jīng)執(zhí)行了停止操作,或者執(zhí)行了重部署操作,此時(shí)是會(huì)生成一個(gè)新的 classLoader 來(lái)加載新部署的應(yīng)用類信息。
我們知道,在 Java 中,類與類之間是存在引用關(guān)系的,類似于強(qiáng)引用,弱引用,幻影引用,用來(lái)在GC時(shí)將一些不需要的 class 回收掉,騰出空間。按理說(shuō)之前的 classLoader 本應(yīng)該被垃圾回收,但在某些時(shí)候,由于一些類之前的引用關(guān)系導(dǎo)致該 classLoader,以及其加載的一系列 class 文件, 都不能被標(biāo)識(shí)為垃圾,此時(shí)這些 class 依然駐留在 Perm Gen,隨著應(yīng)用多次啟停,多次重部署之后,出現(xiàn)了 Perm Gen 的 OOM。
一般以下類庫(kù)的使用容易導(dǎo)致 class loader 逃過(guò)垃圾回收,產(chǎn)生內(nèi)存泄漏:
- JDBC driver 注冊(cè)
- 一些 logging 框架
- 沒(méi)有移除的 ThreadLocal的使用
- 未停止的 Thread
此外,一些 Java API 的使用也容易導(dǎo)致此問(wèn)題,例如
- javax.imageio API
- XML 解析
- RMI 使用
由于這些容易占用 classLoader,導(dǎo)致其不能被回收,如果這些 class 交給各個(gè)應(yīng)用的類加載器進(jìn)行加載,就會(huì)使得 Perm Gen 中這些類越來(lái)越多,從而產(chǎn)生泄漏。
為此,在 Tomcat 中引入了JreMemoryLeakPreventionListener 這個(gè)組件。實(shí)現(xiàn)思路是在 Tomcat 啟動(dòng)時(shí),通過(guò) System class Loader 來(lái)加載這些類。 由于類加載器的加載原理(默認(rèn)父優(yōu)先,而且這些系統(tǒng)的類,都會(huì)委托給系統(tǒng)類加載器進(jìn)行加載),這些類不會(huì)再被 WebclassLoader 重新加載,從而減小內(nèi)存泄漏的產(chǎn)生。
默認(rèn)在 Tomcat 的配置 server.xml 中已經(jīng)開(kāi)啟了該組件,所以這些功能你已經(jīng)不知不覺(jué)中在使用。
【本文為專欄作者“侯樹(shù)成”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過(guò)作者微信公眾號(hào)『Tomcat那些事兒』獲取授權(quán)】
戳這里,看該作者更多好文
網(wǎng)頁(yè)名稱:Tomcat與內(nèi)存泄露處理
轉(zhuǎn)載注明:http://m.fisionsoft.com.cn/article/copdhse.html


咨詢
建站咨詢
