2012年6月23日
今天追蹤一個關于頁面內存暴漲,頁面響應過慢的問題。花了4個多小時,總算找到問題出在哪了。
一、問題描述
最近我們在一臺獨享服務器上搭建了Tomcat6.0.19環境,發現訪問首頁時,內存暴漲,一直不退。每次刷新內存增加近10M。一個人狂刷新一分鐘就可以把tomcat搞死機。
然后,找各種辦法解決問題。整了幾天,每天中午輪流監控Tomcat服務器,發現它掛了后就重啟。累壞了。
每天到google上面搜索答案,有人說是程序的問題,程序內存泄露。甚至問到“有沒有數據庫沒有釋放”、“有沒有使用死循環”、有沒有寫“System.gc()自動釋放內存”、有沒有“在Service層查詢時使用all()方法,查處了所有記錄”。等等。
而我一直不承認程序有問題。理由是:我們曾經將這個程序在租用的2個虛擬主機中用了近1個月。不斷維護,最后達到一個星期沒有出現一個異常的情況。
二、問題分析(關于tomcat內存溢出問題)
分析Tomcat死機的日志,發現是內存耗盡。
大致有這么一段,PSPermGen total 86016K used 86015K
到網上搜了一下,明白了jvm內存分類。然后配置內存,讓tomcat自動回收jvm內存。
當然,配置過程也遇到了很多問題,花了一天多。問題是網上的很多人都是抄來抄去,要在一大堆垃圾中選出精品不容易呀。
配了一天都只起到一定作用。比如:給tomcat設置較大內存后,tomcat可以承受到2.19G。只是再刷新就可以把他整崩潰。
最后,請了幾個牛人幫忙,一個牛人凌晨幫我們看tomcat配置。問我們,是否加了,-server參數。最后,我同事加上了-server參數。 然后,回去睡覺了,發現java.exe內存真的能回收了。很多問題也解決了。
我們配置如下:(將tomcat6的安裝版卸載,換成綠色版)
在catalina.bat的@echo off下面添加(就是第二行)
set JAVA_OPTS=-server -Xms512m -Xmx1024m -XX:MaxNewSize=512m -XX:MaxPermSize=256m
在startup.bat下面添加(讓tomcat的工具自動回收內存)
@echo off
set JAVA_OPTS=%JAVA_OPTS%
-Dcom.sun.management.jmxremote.port=1090
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djava.util.logging.config.file="%CATALINA_HOME%\conf\logging.properties"
三、問題分析(關于頁面反應速度異常)
我們的首頁顯示餐館的信息,主要根據用戶選擇地區,然后將該地區的餐館列表和熱賣美食列表顯示出來。我們發現一個很奇怪的現象,訪問某一學校東校區時:
8個餐館:Action執行2063ms(獲取餐館列表:1220ms + 獲取熱賣美食:825ms)。
然后換成其他校區分別為:
3個餐館:Action執行 51ms (獲取餐館列表:29 + 獲取熱賣美食: 2)
3個餐館:Action執行 53ms (32 + 1)
4個餐館:Action執行 90ms (74 + 1)
看到這個數據,我就很納悶,怎么時間不成比例呢?
于是,我將8個餐館刪掉4個對比。由于有外鍵關聯,我必須要刪除其他的很多的。為了刪除一個餐館記錄,我必須刪除其他記錄多達6個表處,可見外鍵關系較為復雜。
等我刪掉后,發現東校區:
4個餐館:Action執行111ms(獲取餐館列表:53ms + 獲取熱賣美食:37ms)。
我發現這個變化太明顯了吧。然后,我懷疑那四個餐館關聯了太多東西。我查詢出來的不僅僅是餐館,可能連帶查詢了另外的6個表的記錄。
我就想到了是hbm.xml文件中設置lazy = "true"問題。
通過測試,我發現是 餐館對應訂單時,one-to-many時,lazy = "true"。這個就很明顯了。
查詢一個餐館,就把它的上百份訂單級聯查詢出來了,同時把所有菜品也級聯查詢出來了,把所有菜品分類都查詢出來了。
而就東校區的這8家餐館訂單較多,其他校區由于剛開業,訂單幾乎沒有。這下就可以解釋為什么東校區這么耗時間(當然也耗內存)。
然后,我將hbm.xml的所有lazy="true"全部去掉,恢復數據庫數據。
東校區結果如下:
8個餐館:Action執行25ms(獲取餐館列表:3ms + 獲取熱賣美食:8ms)。
四、結論:
lazy="false"使用時要慎重。例如:對與1:1的情況,使用直接影響不大,對于1:n情況就要慎重了。尤其是n成百上千時,問題就相當嚴重了。我建議最好不用。
第一次,配置和管理服務器,收獲真大呀。對我以后的編程風格都造成了深遠的影響。我會注意服務器的時間和空間效率問題。
當然測試方法比較土。先將服務器正常上線后,我會學著使用JMeter和roadrunner的工具做壓力測試,配置好服務器。
忙里偷閑!記錄下來!
轉自http://www.cnblogs.com/pyrmkj/archive/2012/06/23/2559375.html