最近遇到個(gè)麻煩事, oc4j跑一天就到max heap size了。然后容器中有些servlet運(yùn)行就不正常了(表現(xiàn)為有些業(yè)務(wù)能用有些則不能,而且系統(tǒng)表現(xiàn)的其慢無(wú)比),所以個(gè)人最開(kāi)始估計(jì)是1.分配內(nèi)存失敗,因?yàn)橛袝r(shí)會(huì)打出OutOfMemory,2.很多socket超時(shí),因?yàn)?/span>%70都在做gc(yc,fc). 為了找到并驗(yàn)證這個(gè)問(wèn)題,就把jre換成了jrrt(據(jù)說(shuō)效率會(huì)提高很多倍,最主要是容易找內(nèi)存泄漏的問(wèn)題),而客戶(hù)端用jmc來(lái)進(jìn)行線(xiàn)程堆棧和內(nèi)存分析. 但首先遇到的問(wèn)題就是: 由于是移動(dòng)的項(xiàng)目,服務(wù)器在移動(dòng)機(jī)訪(fǎng),對(duì)外網(wǎng)訪(fǎng)問(wèn)服務(wù)器有嚴(yán)格的控制,想要開(kāi)一些端口,得走很長(zhǎng)的開(kāi)端口流程。目前oc4j幾乎每天都會(huì)出問(wèn)題,于是等不了那么久了。 因?yàn)槲矣蟹?wù)器root權(quán)限,所有想繞過(guò)這個(gè)限制就很easy了。下面介始兩種方法,讓無(wú)論客戶(hù)機(jī)是linux還是windows都可以把jmc用起來(lái)。
一、用tunnels技術(shù)
第一步:下載jrrt.
第二步: oc4j 啟動(dòng)參數(shù)設(shè)成: java -Xmx2000m -server -Djava.awt.headless=true -verbosegc -Dcom.sun.management.jmxremote.port=6666 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=localhost -Dstdstream.filesize=100 -Dstdstream.filenumber=1000 -jar oc4j.jar -userThreads -out /opt/lbsonelog/oc4j.out -err /opt/lbsonelog/oc4j.err
記的要把$JRE_HOME改成jrrt的路徑, 改好后啟動(dòng)。再運(yùn)行jrcmd pid memleakserver, 目得是監(jiān)聽(tīng)tcp-7095 端口, 沒(méi)有這個(gè)端口,是不能檢查內(nèi)存泄漏的。
第三步:如果是windows,那么下載putty(securecrt不行,不支持tunnels),如果是linux則用ssh就可以了。
第四步:1.putty配置tunnels的方法, 6666--->localhost:6666, 用netstat -tnpl查看隨機(jī)端口, 然后 隨機(jī)端口---->localhost:隨機(jī)端口 (只有前面這兩個(gè)端口能連上,才能在jmc中測(cè)試連接成功。切記) 7095-->localhost:7095 (用來(lái)檢查內(nèi)存泄漏的)。 2.linux下的ssh為ssh -L port:host:hostport -l login_name ip 比如:ssh -L 5901:localhost:5901 -l gate 211.x.x.x
第五步: 下載jmc
第六步:運(yùn)行jmc, 新建連接中填 localhost, 6666. 測(cè)試連接,如果顯示確定。 就表示成功了。
二、用vnc(前提是有一個(gè)開(kāi)放的端口或先用上面的方法把這個(gè)端口做tunnel)
1、想改端口的話(huà),可以在/usr/bin/vncserver中先定義$default_port=9000;然后找到5900后用$default_port替換。然后監(jiān)聽(tīng)的端口就成了,9000+N了。
2、在/root/.vnc/xstartup中,把最后一行twm&(vnc支持的不好)改成 gnome-session &。
3、如果讓display固定在1, 那么可以刪除 /tmp的.X*-lock,和/tmp/.X11-unix下的所有文件。
4、用vncviewer 直接連接服務(wù)器上的端口或者連接用tunnel做的localhost端口。
5、裝上linux下的jmc,在本地那里自動(dòng)會(huì)出現(xiàn)oc4j.
通過(guò)上面的兩種方法都可以跑起來(lái)。兩種我都玩過(guò)了,都沒(méi)什么問(wèn)題。
最后用jmc分析后,發(fā)現(xiàn)占用內(nèi)存最多的是[B, [C(就是byte[]和char []),占了目前堆的80%以上,直接點(diǎn)右鍵進(jìn)堆棧,發(fā)現(xiàn)來(lái)自oracle.jdbc上面,為什么呢?然后go oracle官網(wǎng),通過(guò)一翻搜索,最終得到的結(jié)論是oc4j的數(shù)據(jù)庫(kù)連接池配置不對(duì),一看目前配置的是connection: mix:200-max:10000, stmt-cach-size:200, stmt cach的意思是為了提高效率,oracle.jdbc會(huì)自己存一份引用,所以在應(yīng)用層就是close了,如果一個(gè)連接沒(méi)超過(guò)200這個(gè)數(shù),也是不會(huì)gc的,所以只要跑一段時(shí)間后,內(nèi)存的占用就成了: 當(dāng)前連接數(shù)(一般出問(wèn)題時(shí)這個(gè)都超過(guò)1000) * 200 * 每條sql查出的數(shù)據(jù)的大小,如果一個(gè)語(yǔ)句查出的結(jié)果是5K, 那么這個(gè)內(nèi)存占用可真不小了,1個(gè)g呀,我的個(gè)媽呀,真是害人不淺呀。然后就把connection設(shè)成10-100,stmt-cach-size:10。然后又看了下目前運(yùn)行的線(xiàn)程,直覺(jué)告我不太正常,分析之,發(fā)現(xiàn)有個(gè)線(xiàn)程會(huì)把前面的connection的數(shù)量一下提搞到很高,而且線(xiàn)程sleep很短,結(jié)果會(huì)造成創(chuàng)建出的connection要遠(yuǎn)遠(yuǎn)快于gc回收的connection,經(jīng)過(guò)一段時(shí)間后,就會(huì)出現(xiàn)最開(kāi)始說(shuō)的60%的時(shí)間用在了gc上,一gc就會(huì)把所有線(xiàn)程鎖死,所以表現(xiàn)為有些業(yè)務(wù)不正常了。馬上想了個(gè)好辦法修改之。然后啟動(dòng)oc4j通過(guò)一晚上的奔跑,內(nèi)存大部分時(shí)間都穩(wěn)定在200m左右。成功解決此問(wèn)題。