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