摘要:如果發(fā)現(xiàn)某類對(duì)象占用內(nèi)存很大例如幾個(gè),很可能是類對(duì)象創(chuàng)建太多,且一直未釋放。
OOM(OutOfMemoryError) 問(wèn)題歸根結(jié)底三點(diǎn)原因:
本身資源不夠
申請(qǐng)的內(nèi)存太多
資源耗盡
解決思路,換成Java服務(wù)分析,三個(gè)原因也可以解讀為:
有可能是內(nèi)存分配確實(shí)過(guò)小,而正常業(yè)務(wù)使用了大量?jī)?nèi)存
某一個(gè)對(duì)象被頻繁申請(qǐng),卻沒有釋放,內(nèi)存不斷泄漏,導(dǎo)致內(nèi)存耗盡
某一個(gè)資源被頻繁申請(qǐng),系統(tǒng)資源耗盡,例如:不斷創(chuàng)建線程,不斷發(fā)起網(wǎng)絡(luò)連接
因此,針對(duì)解決思路,快速定位OOM問(wèn)題的三板斧是:
確認(rèn)是不是內(nèi)存本身就分配過(guò)小
找到最耗內(nèi)存的對(duì)象
確認(rèn)是否是資源耗盡
以正式線上的tomcat為例,tomcat運(yùn)行5個(gè)ssm架構(gòu)的java項(xiàng)目,啟動(dòng)時(shí)需要60秒左右,運(yùn)行一段時(shí)間偶爾會(huì)有OOM出現(xiàn),現(xiàn)在逐一排查:
(1) 確認(rèn)是不是內(nèi)存本身就分配過(guò)小
在服務(wù)器(8核16G)上輸入 top 查看 java啟動(dòng)時(shí)內(nèi)存變化情況,順便找到j(luò)ava的進(jìn)程ID : 10397
然后, 輸入:jmap -heap 10397,觀察堆、新生代、老年代的內(nèi)存使用情況,發(fā)現(xiàn)大概都用了一半,可以確定,不是內(nèi)存分配過(guò)小問(wèn)題。
wen@S189919:/opt/tomcat8$ jmap -heap 1246 Attaching to process ID 1246, please wait... Debugger attached successfully. Server compiler detected. JVM version is 24.65-b04 using thread-local object allocation. Parallel GC with 8 thread(s) Heap Configuration: MinHeapFreeRatio = 0 MaxHeapFreeRatio = 100 MaxHeapSize = 4208984064 (4014.0MB) NewSize = 1310720 (1.25MB) MaxNewSize = 17592186044415 MB OldSize = 5439488 (5.1875MB) NewRatio = 2 SurvivorRatio = 8 PermSize = 21757952 (20.75MB) MaxPermSize = 85983232 (82.0MB) G1HeapRegionSize = 0 (0.0MB) Heap Usage: PS Young Generation Eden Space: capacity = 1172307968 (1118.0MB) used = 679248008 (647.781379699707MB) free = 493059960 (470.21862030029297MB) 57.94108941857845% used From Space: capacity = 85983232 (82.0MB) used = 0 (0.0MB) free = 85983232 (82.0MB) 0.0% used To Space: capacity = 115343360 (110.0MB) used = 0 (0.0MB) free = 115343360 (110.0MB) 0.0% used PS Old Generation capacity = 259522560 (247.5MB) used = 147065016 (140.25212860107422MB) free = 112457544 (107.24787139892578MB) 56.667526707504734% used PS Perm Generation capacity = 63963136 (61.0MB) used = 32219528 (30.72693634033203MB) free = 31743608 (30.27306365966797MB) 50.37202678742956% used 16612 interned Strings occupying 2080416 bytes.
(2) 找到最耗內(nèi)存的對(duì)象
jmap -histo:live 1246| more
輸入命令后,會(huì)以表格的形式顯示存活對(duì)象的信息,并按照所占內(nèi)存大小排序:
實(shí)例數(shù)
所占內(nèi)存大小
類名
通過(guò)觀察,雖然我不知道 [B 是什么類,但是最大也只有72M,對(duì)內(nèi)存來(lái)說(shuō)簡(jiǎn)直沒有知覺。
如果發(fā)現(xiàn)某類對(duì)象占用內(nèi)存很大(例如幾個(gè)G),很可能是類對(duì)象創(chuàng)建太多,且一直未釋放。例如:
申請(qǐng)完資源后,未調(diào)用close()或dispose()釋放資源
消費(fèi)者消費(fèi)速度慢(或停止消費(fèi)了),而生產(chǎn)者不斷往隊(duì)列中投遞任務(wù),導(dǎo)致隊(duì)列中任務(wù)累積過(guò)多
wen@S189919:/opt/tomcat8$ jmap -histo:live 1246 | more num #instances #bytes class name ---------------------------------------------- 1: 79073 72095344 [B 2: 103049 13630576 [C 3: 57516 81553284: 57516 7373456 5: 5413 6128216 6: 5413 3861128 7: 4455 3264960 8: 101128 2427072 java.lang.String 9: 46704 1868160 java.lang.ref.Finalizer 10: 5314 1486584 [Ljava.util.HashMap$Entry; 11: 22264 1419160 [Ljava.lang.Object; 12: 17286 1382880 java.lang.reflect.Method 13: 20810 1165360 java.util.zip.ZipFile$ZipFileInputStream 14: 20389 1141784 java.util.zip.ZipFile$ZipFileInflaterInputStream 15: 34592 1106944 java.util.HashMap$Entry 16: 1963 1075048 17: 1762 943992 [I 18: 22136 708352 java.util.concurrent.ConcurrentHashMap$HashEntry 19: 5866 704008 java.lang.Class 20: 14549 581960 java.util.LinkedHashMap$Entry 21: 21158 507792 java.util.ArrayList 22: 7742 453448 [S 23: 8839 450464 [[I 24: 7362 412272 java.util.LinkedHashMap 25: 3735 328416 [Ljava.util.concurrent.ConcurrentHashMap$HashEntry; 26: 14544 322536 [Ljava.lang.Class; 27: 7350 294000 com.sun.org.apache.xerces.internal.dom.DeferredTextImpl 28: 2973 273488 [Ljava.util.WeakHashMap$Entry; 29: 6660 266400 com.sun.org.apache.xerces.internal.dom.DeferredAttrImpl 30: 5394 258912 java.util.HashMap 31: 6441 257640 javax.servlet.jsp.tagext.TagAttributeInfo 32: 436 237184 33: 14200 227200 java.lang.Object 34: 2783 222640 sun.net.www.protocol.jar.URLJarFile 35: 3914 219184 com.sun.org.apache.xerces.internal.dom.DeferredElementImpl 36: 6016 192512 java.util.concurrent.locks.ReentrantLock$NonfairSync 37: 4328 173120 java.lang.ref.SoftReference 38: 2970 166320 java.util.WeakHashMap 39: 3200 153184 [Ljava.lang.String; 40: 3735 149400 java.util.concurrent.ConcurrentHashMap$Segment
(3) 確認(rèn)是否是資源耗盡
通過(guò)查看 sshd 進(jìn)程,得出句柄詳情和線程數(shù)
/proc/${PID}/fd
/proc/${PID}/task
最終的結(jié)果句柄數(shù)和線程數(shù)8和4,更不可能引發(fā)內(nèi)存溢出
root@S189919:/home/wen# ps -aux | grep sshd Warning: bad ps syntax, perhaps a bogus "-"? See http://procps.sf.net/faq.html root 749 0.0 0.0 50036 2928 ? Ss 19:01 0:00 /usr/sbin/sshd -D root 1321 0.0 0.0 73440 3608 ? Ss 19:15 0:00 sshd: wen [priv] wen 1464 0.0 0.0 73440 1528 ? S 19:15 0:00 sshd: wen@pts/0 root 1585 0.0 0.0 9388 940 pts/0 S+ 19:20 0:00 grep --color=auto sshd root@S189919:/home/wen# ll /proc/749/fd total 0 dr-x------ 2 root root 0 Sep 4 19:01 ./ dr-xr-xr-x 8 root root 0 Sep 4 19:01 ../ lrwx------ 1 root root 64 Sep 4 19:01 0 -> /dev/null lrwx------ 1 root root 64 Sep 4 19:01 1 -> /dev/null lrwx------ 1 root root 64 Sep 4 19:01 2 -> /dev/null lr-x------ 1 root root 64 Sep 4 19:01 3 -> socket:[7330] lrwx------ 1 root root 64 Sep 4 19:21 4 -> socket:[7332] root@S189919:/home/wen# ll /proc/749/task total 0 dr-xr-xr-x 3 root root 0 Sep 4 19:21 ./ dr-xr-xr-x 8 root root 0 Sep 4 19:01 ../ dr-xr-xr-x 6 root root 0 Sep 4 19:21 749/ root@S189919:/home/wen# ll /proc/749/fd | wc -l 8 root@S189919:/home/wen# ll /proc/749/task | wc -l
(4) 合并相同的 jar 包
最后,想來(lái)想去,很有可能是項(xiàng)目啟動(dòng)時(shí)加載太多第三方j(luò)ar包,于是,將5個(gè)ssm的jar包合并,覆蓋掉相同的,放在tomcat的shared lib目錄:
修改 ${ TOMCAT_HOME }/conf/catalina.properties文件中shared.loader= ${catalina.base}/shared/lib,${catalina.base}/shared/lib/*.jar 也可以將公用的jar全部放置${ TOMCAT_HOME }/lib包下
1
啟動(dòng)tomcat,加載完用了37秒,但愿能解決OOM問(wèn)題,從此不再被領(lǐng)導(dǎo)說(shuō)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69485.html
摘要:運(yùn)行模式分種模式一般使用模式效率低對(duì)系統(tǒng)配置有一些比較高的要求確認(rèn)的運(yùn)行模式配置文件關(guān)鍵配置最大線程數(shù)默認(rèn)是最小活躍線程數(shù)默認(rèn)是最大的等待隊(duì)列個(gè)數(shù),超過(guò)則請(qǐng)求拒絕默認(rèn)值是,一般不改變。 前言 Tomcat作為Web應(yīng)用的服務(wù)器,目前絕大多數(shù)公司都是用其作為應(yīng)用服務(wù)器的,應(yīng)用服務(wù)器的執(zhí)行效率會(huì)影響系統(tǒng)執(zhí)行,這里會(huì)講Tomcat怎樣進(jìn)行配置能提高處理性能。另外必須提到對(duì)應(yīng)的JVM參數(shù)的優(yōu)化...
摘要:也正是因此,一旦出現(xiàn)內(nèi)存泄漏或溢出問(wèn)題,如果不了解的內(nèi)存管理原理,那么將會(huì)對(duì)問(wèn)題的排查帶來(lái)極大的困難。 本文已收錄【修煉內(nèi)功】躍遷之路 showImg(https://segmentfault.com/img/bVbsP9I?w=1024&h=580); 不論做技術(shù)還是做業(yè)務(wù),對(duì)于Java開發(fā)人員來(lái)講,理解JVM各種原理的重要性不必再多言 對(duì)于C/C++而言,可以輕易地操作任意地址的...
摘要:服務(wù)本身是一個(gè),開起的線程數(shù)為,再加上一些其他線程,總的線程數(shù)不會(huì)超過(guò)服務(wù)內(nèi)自己沒有顯示創(chuàng)建線程或者使用線程池。問(wèn)題解決找到所在后,結(jié)局方案很簡(jiǎn)單,只需將的通過(guò)單例的方式注入到服務(wù)中,即可解決堆外內(nèi)存泄漏的問(wèn)題。 內(nèi)存泄漏Bug現(xiàn)場(chǎng) 一個(gè)做BI數(shù)據(jù)展示的服務(wù)在一個(gè)晚上重啟了5次,由于是通過(guò)k8s容器編排,服務(wù)掛了以后會(huì)自動(dòng)重啟,所以服務(wù)還能繼續(xù)提供服務(wù)。 第一時(shí)間先上日志系統(tǒng)查看錯(cuò)誤日...
摘要:方法區(qū)溢出在的方法區(qū)中,它主要存放了類的信息,常量,靜態(tài)變量等。運(yùn)行結(jié)果簡(jiǎn)單解決思路一般來(lái)說(shuō)此類問(wèn)題多出現(xiàn)在存在遞歸的地方,要從代碼里重新審視遞歸未結(jié)束的原因,若遞歸的方法沒問(wèn)題可以根據(jù)實(shí)際情況調(diào)整參數(shù)的大小。 前言 如今不管是在面試還是在我們的工作中,OOM總是不斷的出現(xiàn)在我們的視野中,所以我們有必要去了解一下導(dǎo)致OOM的原因以及一些基本的調(diào)整方法,大家可以通過(guò)下面的事例來(lái)了解一下什...
閱讀 839·2021-09-07 09:58
閱讀 2697·2021-08-31 09:42
閱讀 2869·2019-08-30 14:18
閱讀 3095·2019-08-30 14:08
閱讀 1842·2019-08-30 12:57
閱讀 2767·2019-08-26 13:31
閱讀 1307·2019-08-26 11:58
閱讀 1061·2019-08-23 18:06