內(nèi)存泄漏問題
某個JavaEE應(yīng)用運行在8顆CPU的服務(wù)器上。上線運行發(fā)現(xiàn)性能不穩(wěn)定。性能隨著時間的增加而越來越慢。通過操作系統(tǒng)的工具(mpstat),發(fā)現(xiàn)在系統(tǒng)很慢的時候,只有一顆CPU很忙,其他的CPU都很空閑。因此懷疑是Java虛擬機經(jīng)常進(jìn)行內(nèi)存回收,因為虛擬機在內(nèi)存回收的時候,有的回收算法通常只能運行在一個CPU上。通過Java虛擬機的工具“jstat”可以清楚的看到,Java虛擬機進(jìn)行內(nèi)存回收的頻率非常高,幾乎每5秒中就有一次,每次回收的時間為2秒鐘。另外,通過“jstat”的輸出還發(fā)現(xiàn)每次回收釋放的內(nèi)存非常有限,大多數(shù)對象都無法回收。這種現(xiàn)象很大程度上暗示著內(nèi)存泄漏。使用Java虛擬機的工具“jmap”來獲得當(dāng)前的一個內(nèi)存映象。發(fā)現(xiàn)有很多(超過10000)個的session對象。這是不正常的一個現(xiàn)象。一般來說,session對應(yīng)于一個用戶的多次訪問,當(dāng)用戶退出的時候,session就應(yīng)該失效,對象應(yīng)該被回收。當(dāng)我們和這個系統(tǒng)的開發(fā)工程師了解有關(guān)session的設(shè)置,發(fā)現(xiàn)當(dāng)他們部署應(yīng)用的時候,竟然將session的timeout時間設(shè)置為50分鐘,并且沒有提供logout的接口。這樣的設(shè)置下,每個session的數(shù)據(jù)都會保存50分鐘才會被回收。根據(jù)我們的建議,系統(tǒng)提供了logout的鏈接,并且告訴用戶如果退出應(yīng)用,應(yīng)該點擊這個logout的鏈接;并且將session的timeout時間修改為5分鐘。通過幾天的測試,證明泄漏的問題得到解決。
數(shù)據(jù)庫連接池問題
某財務(wù)應(yīng)用運行在JavaEE服務(wù)器上,后臺連接Oracle數(shù)據(jù)庫。并發(fā)用戶數(shù)量超過100人左右的時候系統(tǒng)停止響應(yīng)。通過操作系統(tǒng)層面的進(jìn)程監(jiān)控工具發(fā)現(xiàn)進(jìn)程并沒有被殺死或掛起,而CPU使用率幾乎為零。那么是什么原因?qū)е孪到y(tǒng)停止響應(yīng)用戶請求呢?我們利用Java虛擬機的工具(kill -3 pid)將當(dāng)前的所有線程狀態(tài)DUMP出來,發(fā)現(xiàn)JavaEE服務(wù)器的大部分處理線程都在等待數(shù)據(jù)庫連接池的連接,而那些已經(jīng)獲得數(shù)據(jù)庫連接的線程卻處于阻塞狀態(tài)。數(shù)據(jù)庫管理員應(yīng)要求檢查了數(shù)據(jù)庫的狀態(tài),發(fā)現(xiàn)所有的連接的session都處于死鎖狀態(tài)。顯然,這是因為數(shù)據(jù)庫端出現(xiàn)了死鎖的操作,阻塞了那些有數(shù)據(jù)庫操作的請求,占用了所有數(shù)據(jù)庫連接池中的連接。后續(xù)的請求如果還要從連接池中獲取連接,就會阻塞在連接池上。當(dāng)解決數(shù)據(jù)庫死鎖的問題之后,性能問題迎刃而解。
大對象緩存問題
電信應(yīng)用運行在64位Java虛擬機上,系統(tǒng)運行得很不穩(wěn)定,系統(tǒng)經(jīng)常停止響應(yīng)。使用進(jìn)程工具查看,發(fā)現(xiàn)進(jìn)程并沒有被殺死或掛起。利用Java虛擬機的工具發(fā)現(xiàn)系統(tǒng)在長時間的進(jìn)行內(nèi)存回收,內(nèi)存回收的時間長達(dá)15分鐘,整個系統(tǒng)在內(nèi)存回收的時候就像掛起一樣。另外還觀察到系統(tǒng)使用了12G的內(nèi)存(因為是64位虛擬機所以突破了4G內(nèi)存的限制)。從開發(fā)人員那里了解到,這個應(yīng)用為了提高性能,大量使用了對象緩存,但是事與愿違,在Java中使用過多的內(nèi)存,雖然在正常運行的時候能夠獲得很好的性能,但是會大大增加內(nèi)存回收的時間。特別是對象緩存,本系統(tǒng)使用了8G的緩存空間,共緩存了6000多萬個對象,對這些對象的遍歷導(dǎo)致了長時間的內(nèi)存回收。根據(jù)我們的建議,將緩存空間減少到1G,并調(diào)整回收算法(使用增量回收的算法),使得系統(tǒng)由于內(nèi)存回收而造成的最大停頓時間減少到4秒,基本滿足用戶的需求。
外部命令問題
數(shù)字校園應(yīng)用運行在4CPU的Solaris10服務(wù)器上,中間件為JavaEE服務(wù)器。系統(tǒng)在做大并發(fā)壓力測試的時候,請求響應(yīng)時間比較慢,通過操作系統(tǒng)的工具(mpstat)發(fā)現(xiàn)CPU使用率比較高。并且系統(tǒng)占用絕大多數(shù)的CPU資源而不是應(yīng)用本身。這是個不正常的現(xiàn)象,通常情況下用戶應(yīng)用的CPU占用率應(yīng)該占主要地位,才能說明系統(tǒng)是正常工作。通過Solaris 10的Dtrace腳本,我們查看當(dāng)前情況下哪些系統(tǒng)調(diào)用花費了最多的CPU資源,竟然發(fā)現(xiàn)最花費CPU的系統(tǒng)調(diào)用是“fork”。眾所周知,“fork”系統(tǒng)調(diào)用是用來產(chǎn)生新的進(jìn)程,在Java虛擬機中只有線程的概念,絕不會有進(jìn)程的產(chǎn)生。這是個非常異常的現(xiàn)象。通過本系統(tǒng)的開發(fā)人員,我們找到了答案:每個用戶請求的處理都包含執(zhí)行一個外部shell腳本,來獲得系統(tǒng)的一些信息。這是通過Java的“Runtime.getRuntime().exec”來完成的,但是這種方法在Java中非常消耗資源。Java虛擬機執(zhí)行這個命令的方式是:首先克隆一個和當(dāng)前虛擬機一樣的進(jìn)程,再用這個新的進(jìn)程去執(zhí)行外部命令,最后再退出這個進(jìn)程。如果頻繁執(zhí)行這個操作,系統(tǒng)的消耗會很大,不僅在CPU,內(nèi)存操作也很重。用戶根據(jù)建議去掉這個shell腳本執(zhí)行的語句,系統(tǒng)立刻回復(fù)了正常。
文件操作問題
內(nèi)容管理(CMS)系統(tǒng)運行在JavaEE服務(wù)器上,當(dāng)系統(tǒng)長時間運行以后,性能非常差,用戶請求的延時比系統(tǒng)剛上線的時候要大很多,并且用戶的并發(fā)量很小,甚至是單個用戶也很慢。通過操作系統(tǒng)的工具觀察,一切都很正常,CPU利用率不高,IO也不是很大,內(nèi)存很富余,網(wǎng)絡(luò)幾乎沒有壓力(因為并發(fā)用戶少)。先不考慮線程互鎖的問題,因為單個用戶性能也不好。通過Java虛擬機觀察也沒有發(fā)現(xiàn)什么問題(內(nèi)存回收很少發(fā)生)。這使得我們不得不使用代碼跟蹤器來全程跟蹤代碼。我們采用了Netbeans的Profiler,跟蹤的結(jié)果非常意外,用戶請求的90%的時間在創(chuàng)建新文件。從系統(tǒng)設(shè)計人員了解到,此系統(tǒng)使用了一個目錄用于保存所有上傳和共享的文件,文件用其命名方式來唯一區(qū)別于其他文件。我們查看了那個文件目錄,發(fā)現(xiàn)該目錄下已經(jīng)擁有80萬個文件了。這時候我們才定位到問題了:在同個目錄下放置太多的文件,在創(chuàng)建新文件的時候,系統(tǒng)的開銷是比較大的,例如為了防止重名,文件系統(tǒng)會遍歷當(dāng)前目錄下所有的文件名等等。根據(jù)我們的建議,將文件分類保存在不同的目錄下,性能有了大幅度的提高。
高速緩存命中率問題
運行在JavaEE服務(wù)器上的ERP系統(tǒng),在CPU充分利用的情況下性能仍然不太好。從操作系統(tǒng)層面上觀察不到什么大問題,而且ERP系統(tǒng)過于復(fù)雜,代碼跟蹤比較困難。于是進(jìn)行了CPU狀態(tài)的進(jìn)一步檢查,發(fā)現(xiàn)CPU的TLB命中率不是很高,于是對Java虛擬機的啟動參數(shù)進(jìn)行了修改,強迫虛擬機使用大尺寸的內(nèi)存頁面,提高TLB的命中率。下面的參數(shù)是在Sun的HOTSPOT中調(diào)整大尺寸(4M)頁面的設(shè)置:
-XX:+AggressiveHeap
-XX:LargePageSizeInBytes=256m
通過調(diào)整,TLB命中明顯提高,性能也得到近40%的提升。
轉(zhuǎn)自:http://developers.sun.com.cn/blog/yutoujava/entry/8
---------------------------------------------------------------------------------------------------------------------------------
說人之短,乃護(hù)己之短。夸己之長,乃忌人之長。皆由存心不厚,識量太狹耳。能去此弊,可以進(jìn)德,可以遠(yuǎn)怨。
http://www.aygfsteel.com/szhswl
------------------------------------------------------------------------------------------------------ ----------------- ---------