久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

又見OutOfMemory——一次內(nèi)存溢出故障診斷全過程 | 聚沙成塔-小哈的記事薄

 木木的陽光 2011-04-01

這是一個(gè)幾月前的案例,,問題比較典型,在分析和事后學(xué)習(xí)的過程中讓我對(duì)本地內(nèi)存溢出有了一定的了解,。在此和大家分享,。

先說一下背景,應(yīng)用環(huán)境是AIX5.3+WebSphere6.0.2.37,。在今年的一季度曾發(fā)生過幾次OOM故障,,當(dāng)時(shí)通過幾次內(nèi)存參數(shù)優(yōu)化,最后確定為“-Xgcprolicy:gencon –Xms512m –Xmx1280m –Xmn200m”,,此后穩(wěn)定了半年,,直到此次再發(fā)生應(yīng)用宕機(jī)。

趕到現(xiàn)場,,發(fā)現(xiàn)profiles目錄下生成有javacore和heapdump文件,,Javacore的第一行“Cause of thread dump : Dump Event "systhrow" (00040000) Detail "java/lang/OutOfMemoryError" received”表明了宕機(jī)的原因是OOM,但是令我困惑的是這段內(nèi)容:

0SECTION       MEMINFO subcomponent dump routine

NULL           =================================

1STHEAPFREE    Bytes of Heap Space Free: 818cb70

1STHEAPALLOC   Bytes of Heap Space Allocated: 20000000

在分配的512MB(十六進(jìn)制20000000)的堆空間中,,有129MB(818cb70)空閑空間,,按理說,這種情況下不該發(fā)生OutOfMemory,。就算有申請(qǐng)一個(gè)大對(duì)象,,同時(shí)JVM堆的新生代由于碎片原因沒有連續(xù)空間滿足要求,那么應(yīng)該發(fā)生堆擴(kuò)展,,所以此次內(nèi)存溢出不是堆(Heap)溢出,,GC日志的分析也支持了這一點(diǎn)。

既然Javacore無法得到有用信息,,我把目光轉(zhuǎn)向了SystemErr.log,,在對(duì)應(yīng)日期的地方,我發(fā)現(xiàn)了大量如下報(bào)錯(cuò):

[8/26/10 14:12:57:860 GMT+08:00] 0000002f SystemErr     R Exception in thread "WebContainer : 1" java.lang.RuntimeException: java.lang.OutOfMemoryError: Failed to create a thread: retVal -1073741830, errno 11

[8/26/10 14:12:57:860 GMT+08:00] 0000002f SystemErr     R     at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:801)

[8/26/10 14:12:57:860 GMT+08:00] 0000002f SystemErr     R     at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:881)

[8/26/10 14:12:57:860 GMT+08:00] 0000002f SystemErr     R     at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1497)

[8/26/10 14:12:57:860 GMT+08:00] 0000002f SystemErr     R Caused by: java.lang.OutOfMemoryError: Failed to create a thread: retVal -1073741830, errno 11

at java.lang.Thread.startImpl(Native Method)

at java.lang.Thread.start(Thread.java:980)

at com.ibm.ws.util.ThreadPool.addThread(ThreadPool.java:630)

at com.ibm.ws.util.ThreadPool$3.run(ThreadPool.java:1148)

at com.ibm.ws.security.util.AccessController.doPrivileged(AccessController.java:63)

at com.ibm.ws.util.ThreadPool.execute(ThreadPool.java:1146)

at com.ibm.ws.util.ThreadPool.execute(ThreadPool.java:1040)

at com.ibm.ws.runtime.WSThreadPool.execute(WSThreadPool.java:151)

at com.ibm.io.async.ResultHandler.startHandler(ResultHandler.java:248)

at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:570)

at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:881)

at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1497)

在事后的學(xué)習(xí)中,,我知道“Java.lang.OutOfMemoryError: unable to create native thread” 這樣的異常是在說,,本地內(nèi)存耗盡,從而新的線程無法創(chuàng)建,。而在當(dāng)時(shí)我第一感覺是操作系統(tǒng)參數(shù)設(shè)置問題,,之前我曾寫過一篇由于nofile參數(shù)導(dǎo)致Too many open file的故障。于是我運(yùn)行如下命令

#lsattr -El sys0 -a maxuproc

maxuproc 128 Maximum number of PROCESSES allowed per user True

然后運(yùn)行chgsys修改默認(rèn)的128為1024,這里我犯了一個(gè)錯(cuò)誤,,WebSphere單個(gè)Server就是一個(gè)Java進(jìn)程,,錯(cuò)誤日志里是不能創(chuàng)建一個(gè)thread,而非process,,與Oracle會(huì)創(chuàng)建多個(gè)oracle進(jìn)程不一樣,。果然兩天后又出現(xiàn)了同樣的問題。

這一次的SystemErr日志中,,除了上述的內(nèi)容,,還多了

[8/24/10 9:55:19:813 GMT+08:00] 00000036 SystemErr     R Exception in thread "WebContainer : 4" java.lang.RuntimeException: java.lang.OutOfMemoryError: Unable to allocate 8192 bytes of direct memory after 5 retries

[8/24/10 9:55:19:813 GMT+08:00] 00000036 SystemErr     R     at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:801)

[8/24/10 9:55:19:813 GMT+08:00] 00000036 SystemErr     R     at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:881)

[8/24/10 9:55:19:813 GMT+08:00] 00000036 SystemErr     R     at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1497)

[8/24/10 9:55:19:813 GMT+08:00] 00000036 SystemErr     R Caused by: java.lang.OutOfMemoryError: Unable to allocate 8192 bytes of direct memory after 5 retries

at java.nio.DirectByteBuffer.(DirectByteBuffer.java:197)

at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:303)

at com.ibm.ws.buffermgmt.impl.WsByteBufferPoolManagerImpl.allocateBufferDirect(WsByteBufferPoolManagerImpl.java:656)

at com.ibm.ws.buffermgmt.impl.WsByteBufferPoolManagerImpl.allocateCommon(WsByteBufferPoolManagerImpl.java:570)

at com.ibm.ws.buffermgmt.impl.WsByteBufferPoolManagerImpl.allocateDirect(WsByteBufferPoolManagerImpl.java:506)

at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:498)

at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:881)

at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1497)

Caused by: java.lang.OutOfMemoryError

at sun.misc.Unsafe.allocateMemory(Native Method)

at java.nio.DirectByteBuffer.(DirectByteBuffer.java:184)

… 7 more

我們可以看到是由于DirectByteBuffer無法分配導(dǎo)致的內(nèi)存溢出,而Native Method指明了這是“本地”的溢出,。通過這兩個(gè)關(guān)鍵字,,我查到了IBM的一份BUG記錄:PK31010: OUTOFMEMORYERROR DUE TO DIRECTBYTEBUFFER,但是我的版本已是最新,,無奈繼續(xù)搜尋,。

在Troubleshooting native memory issues這份文檔中,介紹了3種在WebSphere中最常見的導(dǎo)致OOM的原因,。其中第二個(gè)DirectByteBuffer use就是我們問題的癥結(jié),。

Java 1.4 中添加的新 I/O (NIO) 類引入了一種基于通道和緩沖區(qū)來執(zhí)行 I/O 的新方式。就像 Java 堆上的內(nèi)存支持 I/O 緩沖區(qū)一樣,,NIO 添加了對(duì)直接 ByteBuffer 的支持(使用java.nio.ByteBuffer.allocateDirect() 方法進(jìn)行分配),,ByteBuffer 受本機(jī)內(nèi)存而不是 Java 堆支持。直接 ByteBuffer 可以直接傳遞到本機(jī)操作系統(tǒng)庫函數(shù),,以執(zhí)行 I/O — 這使這些函數(shù)在一些場景中要快得多,,因?yàn)樗鼈兛梢员苊庠?Java 堆與本機(jī)堆之間復(fù)制數(shù)據(jù)。

對(duì)于在何處存儲(chǔ)直接 ByteBuffer 數(shù)據(jù),,很容易產(chǎn)生混淆。應(yīng)用程序仍然在 Java 堆上使用一個(gè)對(duì)象來編排 I/O 操作,,但持有該數(shù)據(jù)的緩沖區(qū)將保存在本機(jī)內(nèi)存中,,Java 堆對(duì)象僅包含對(duì)本機(jī)堆緩沖區(qū)的引用。非直接 ByteBuffer 將其數(shù)據(jù)保存在 Java 堆上的 byte[] 數(shù)組中,。下圖展示了直接與非直接 ByteBuffer 對(duì)象之間的區(qū)別:

直接與非直接 java.nio.ByteBuffer 的內(nèi)存拓?fù)浣Y(jié)構(gòu)

ByteBuffer 內(nèi)存安排

直接 ByteBuffer 對(duì)象會(huì)自動(dòng)清理本機(jī)緩沖區(qū),,但這個(gè)過程只能作為 Java 堆 GC 的一部分來執(zhí)行,因此它們不會(huì)自動(dòng)響應(yīng)施加在本機(jī)堆上的壓力,。GC 僅在 Java 堆被填滿,,以至于無法為堆分配請(qǐng)求提供服務(wù)時(shí)發(fā)生,或者在 Java 應(yīng)用程序中顯式請(qǐng)求它發(fā)生(不建議采用這種方式,,因?yàn)檫@可能導(dǎo)致性能問題),。

發(fā)生垃圾收集的情形可能是,本機(jī)堆被填滿,,并且一個(gè)或多個(gè)直接 ByteBuffers 適合于垃圾收集(并且可以被釋放來騰出本機(jī)堆的空間),,但 Java 堆幾乎總是空的,,所以不會(huì)發(fā)生垃圾收集。

摘自《理解JVM如何使用Windows和Linux上的本機(jī)內(nèi)存》

解決此問題的方法,,在文檔中給出的是禁止異步A/O,,通過在Web Container中設(shè)置參數(shù)來避免上節(jié)中所出現(xiàn)的由于Java堆空閑而不發(fā)生垃圾回收,導(dǎo)致本地堆撐滿的情況,。

Servers -> Application Servers -> serverName -> Web Container Settings -> Web Container -> Custom Properties:

Press New:

Add the following pair:

Name: com.ibm.ws.webcontainer.channelwritetype

Value: sync

Press OK, and then save the configuration.

添加此屬性后應(yīng)用又恢復(fù)正常,,但是原先提高性能的特性反而導(dǎo)致內(nèi)存溢出,違背了初衷,,現(xiàn)在的做法只能算一個(gè)妥協(xié),。我會(huì)繼續(xù)查找此問題的解決方法,最不濟(jì)也要有個(gè)使用NIO的Best Practice,。

文檔中另兩個(gè)容易導(dǎo)致本地堆OOM的原因是:

過大的堆上限

Memory layout of a vm in the os





我們知道32位機(jī)器單個(gè)進(jìn)程可以訪問的內(nèi)存地址空間為4G,,如右圖所示,但實(shí)際情況下Windows系統(tǒng)由于內(nèi)核態(tài)和用戶態(tài)的劃分,,用戶態(tài)只有2G的空間,,Linux和AIX的可用空間大一點(diǎn),但也在3G左右,。,,由于JVM實(shí)例進(jìn)程尋址是一定的,所以Heap大小和Native Area此消彼長,。而Native Area中有一部分就是供給線程的內(nèi)存空間,。

“應(yīng)用程序中的每個(gè)線程都需要內(nèi)存來存儲(chǔ)器堆棧(用于在調(diào)用函數(shù)時(shí)持有局部變量并維護(hù)狀態(tài)的內(nèi)存區(qū)域)。每個(gè) Java 線程都需要堆??臻g來運(yùn)行,。根據(jù)實(shí)現(xiàn)的不同,Java 線程可以分為本機(jī)線程和 Java 堆棧,。除了堆??臻g,每個(gè)線程還需要為線程本地存儲(chǔ)(thread-local storage)和內(nèi)部數(shù)據(jù)結(jié)構(gòu)提供一些本機(jī)內(nèi)存,。堆棧大小因 Java 實(shí)現(xiàn)和架構(gòu)的不同而不同,。一些實(shí)現(xiàn)支持為 Java 線程指定堆棧大小,其范圍通常在 256KB 到 756KB 之間,?!?/p>

1.5后一般線程堆棧大小為1M,“對(duì)于擁有數(shù)百個(gè)線程的應(yīng)用程序來說,,線程堆棧的總內(nèi)存使用量可能非常大,。如果運(yùn)行的應(yīng)用程序的線程數(shù)量比可用于處理它們的處理器數(shù)量多,效率通常很低,并且可能導(dǎo)致糟糕的性能和更高的內(nèi)存占用”(摘自《理解JVM如何使用Windows和Linux上的本機(jī)內(nèi)存》)

解決此問題的方法:設(shè)置恰當(dāng)?shù)腏VM最大堆,,32位不要超過1.5G,;設(shè)置恰當(dāng)?shù)木€程池大小(一般50~100),,當(dāng)線程使用較多時(shí),, 使用-Xss256k參數(shù)設(shè)置線程指定堆棧大小(IBM JDK還可以使用-Xmso ××k來設(shè)置Stack size for OS Threads 32-bit),;更換64位的JDK,。

第三個(gè)原因是線程池的TLS泄漏

這個(gè)現(xiàn)象我倒沒見到過,如果你的thread dump里下面三個(gè)屬性里的值有大于300,,那么就要注意了

"WebContainer : 1003" (TID:0×37D62000

"Default : 338" (TID:109934D0

"TCPChannel.DCS : 303" (TID:0×4D720000

解決的方法是設(shè)置線程池的最小最大值一致,。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多