OOM
在其他語(yǔ)言類(lèi)似于C,Delphi等等由于內(nèi)存都是由自己分配和管理,因此內(nèi)存泄露的問(wèn)題比較常見(jiàn),同時(shí)也是很頭痛的一件事情。而Java的對(duì)象生命周期管理都是JVM來(lái)做的,簡(jiǎn)化了開(kāi)發(fā)人員的非業(yè)務(wù)邏輯的處理,但是這種自動(dòng)管理回收機(jī)制也是基于一些規(guī)則的,而違背了這些規(guī)則的時(shí)候,就會(huì)造成所謂的“Memory Leak”。
OOM(Java Heap)
錯(cuò)誤提示:java.lang.OutOfMemoryError。
這類(lèi)OOM是由于JVM分配的給應(yīng)用的Heap Memory已經(jīng)被耗盡,可能是因?yàn)閼?yīng)用在高負(fù)荷的情況下的卻需要很大的內(nèi)存,因此可以通過(guò)修改JVM參數(shù)來(lái)增加Java Heap Memory(不過(guò)也不能無(wú)限制增加,后面那種OOM有可能就是因?yàn)檫@個(gè)原因而產(chǎn)生)。另一種情況是因?yàn)閼?yīng)用程序使用對(duì)象或者資源沒(méi)有釋放,導(dǎo)致內(nèi)存消耗持續(xù)增加,最后出現(xiàn)OOM,這類(lèi)問(wèn)題引起的原因往往是應(yīng)用已不需要的對(duì)象還被其他有效對(duì)象所引用,那么就無(wú)法釋放,可能是業(yè)務(wù)代碼邏輯造成的(異常處理不夠例如IO等資源),也可能是對(duì)于第三方開(kāi)源項(xiàng)目中資源釋放了解不夠?qū)е率褂靡院筚Y源沒(méi)有釋放(例如JDBC的ResultSet等)。
幾個(gè)容易出現(xiàn)問(wèn)題的場(chǎng)景:
1.應(yīng)用的緩存或者Collection:如果應(yīng)用要緩存Java對(duì)象或者是在一個(gè)Collection中保存對(duì)象,那么就要確定是否會(huì)有大量的對(duì)象存入,要做保護(hù),以防止在大數(shù)據(jù)量下大量?jī)?nèi)存被消耗,同時(shí)要保證Cache的大小不會(huì)無(wú)限制增加。
2.生命周期較長(zhǎng)的對(duì)象:盡量簡(jiǎn)短對(duì)象的生命周期,現(xiàn)在采用對(duì)象的創(chuàng)建釋放代價(jià)已經(jīng)很低,同時(shí)作了很好的優(yōu)化,要比創(chuàng)建一個(gè)對(duì)象長(zhǎng)期反復(fù)使用要好。如果能夠設(shè)置超時(shí)的情景下,盡量設(shè)置超時(shí)。
3.類(lèi)似于JDBC的Connection Pool,在使用Pool中的對(duì)象以后需要釋放并返回,不然就會(huì)造成Pool的不斷增大,在其他Pool中使用也是一樣。同樣ResultSet,IO這類(lèi)資源的釋放都需要注意。
解決的方法就是查找錯(cuò)誤或者是增加Java Heap Memory。對(duì)于此類(lèi)問(wèn)題檢測(cè)工具相當(dāng)多,這里就不做介紹了。
OOM(Native Heap)
錯(cuò)誤提示:requested XXXX bytes for ChunkPool::allocate. Out of swap space。
Native Heap Memory是JVM內(nèi)部使用的Memory,這部分的Memory可以通過(guò)JDK提供的JNI的方式去訪問(wèn),這部分Memory效率很高,但是管理需要自己去做,如果沒(méi)有把握最好不要使用,以防出現(xiàn)內(nèi)存泄露問(wèn)題。JVM 使用Native Heap Memory用來(lái)優(yōu)化代碼載入(JTI代碼生成),臨時(shí)對(duì)象空間申請(qǐng),以及JVM內(nèi)部的一些操作。這次同事在壓力測(cè)試中遇到的問(wèn)題就是這類(lèi)OOM,也就是這類(lèi)Memory耗盡。同樣這類(lèi)OOM產(chǎn)生的問(wèn)題也是分成正常使用耗盡和無(wú)釋放資源耗盡兩類(lèi)。無(wú)釋放資源耗盡很多時(shí)候不是程序員自身的原因,可能是引用的第三方包的缺陷,例如很多人遇到的Oracle 9 JDBC驅(qū)動(dòng)在低版本中有內(nèi)存泄露的問(wèn)題。要確定這類(lèi)問(wèn)題,就需要去觀察Native Heap Memory的增長(zhǎng)和使用情況,在服務(wù)器應(yīng)用起來(lái)以后,運(yùn)行一段時(shí)間后JVM對(duì)于Native Heap Memory的使用會(huì)達(dá)到一個(gè)穩(wěn)定的階段,此時(shí)可以看看什么操作對(duì)于Native Heap Memory操作頻繁,而且使得Native Heap Memory增長(zhǎng),對(duì)于Native Heap Memory的情況我還沒(méi)有找到辦法去檢測(cè),現(xiàn)在能夠看到的就是為JVM啟動(dòng)時(shí)候增加-verbose:jni參數(shù)來(lái)觀察對(duì)于Native Heap Memory的操作。另一種情況就是正常消耗Native Heap Memory,對(duì)于Native Heap Memory的使用主要取決于JVM代碼生成,線程創(chuàng)建,用于優(yōu)化的臨時(shí)代碼和對(duì)象產(chǎn)生。當(dāng)正常耗盡Native Heap Memory時(shí),那么就需要增加Native Heap Memory,此時(shí)就會(huì)和我們前面提到增加java Heap Memory的情況出現(xiàn)矛盾。
應(yīng)用內(nèi)存組合
對(duì)于應(yīng)用來(lái)說(shuō),可分配的內(nèi)存受到OS的限制,不同的OS對(duì)進(jìn)程所能訪問(wèn)虛擬內(nèi)存地址區(qū)間直接影響對(duì)于應(yīng)用內(nèi)存的分配,32位的操作系統(tǒng)通常最大支持4G的內(nèi)存尋址,而Linux一般為3G,Windows為2G。然而這些大小的內(nèi)存并不會(huì)全部給JVM的Java Heap使用,它主要會(huì)分成三部分:Java Heap,Native Heap,載入資源和類(lèi)庫(kù)等所占用的內(nèi)存。那么由此可見(jiàn),Native Heap和 Java Heap大小配置是相互制約的,哪一部分分配多了都可能會(huì)影響到另外一部分的正常工作,因此如果通過(guò)命令行去配置,那么需要確切的了解應(yīng)用使用情況,否則采用默認(rèn)配置自動(dòng)監(jiān)測(cè)會(huì)更好的優(yōu)化應(yīng)用使用情況。
同樣要注意的就是進(jìn)程的虛擬內(nèi)存和機(jī)器的實(shí)際內(nèi)存還是有區(qū)別的,對(duì)于機(jī)器來(lái)說(shuō)實(shí)際內(nèi)存以及硬盤(pán)提供的虛擬內(nèi)存都是提供給機(jī)器上所有進(jìn)程使用的,因此在設(shè)置JVM參數(shù)時(shí),它的虛擬內(nèi)存絕對(duì)不應(yīng)該超過(guò)實(shí)際內(nèi)存的大小。
待續(xù)……
JVM優(yōu)化配置
更多內(nèi)容可訪問(wèn):http://blog.csdn.net/cenwenchu79/