引入:
我們有時候經常遇到Liferay運行一段時間之後伺服器癱瘓了,這時候其實很希望的做法就是用管理員登陸Liferay控制台中(Dockbar->Control Panel->Server->Service Administration)然後即時調用一些操作,比如記憶體回收,緊接著,我們就可以從儀錶盤中看到更新後伺服器的記憶體情況或者其他情況了。那麼這其中隱藏什麼樣的秘密呢?比如如何做到記憶體回收呢?儀錶盤是如何更新呢?
調試分析:
我們還是從前端開始,當我們初次去看Liferay伺服器系統資訊時候,看到的記憶體開銷如下:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GG247-0.png" title="31.png" />
當我們點擊下方的動作:比如說gc:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GH0b-1.png" title="32.png" />
它會去觸發struts action為/admin_server/edit_server,並且命令cmd為gc
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GM501-2.png" title="33.png" />
我們很容易在struts-config.xml中找到對應的Action類為EditServerAction:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GK964-3.png" title="34.png" />
因為我們的 cmd是gc,所以會走以下分支:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GJ255-4.png" title="35.png" />
並且調用gc()方法:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GI139-5.png" title="36.png" />
這可以看出,實際它是調用當前應用對應的運行時,讓其調用gc()方法來強制進行記憶體回收。關於這個Runtime.getRuntime.gc()和System.gc()區別我不想再說了,相關文章一大堆。
我們現在來研究更感興趣的話題,當這個gc()記憶體回收完成之後,怎麼去更新系統資訊儀錶盤。很容易就找到,其實這個儀錶盤對應的代碼是在server.jspf 這個頁幀中因為我們的tab選的是"server"):
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GMS1-6.png" title="37.png" />
我們跳過許多不重要的行,可以發現,直到第656行,就開始為下面的儀錶盤準備資料了:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GL0Z-7.png" title="42.png" />
首先,第656到第660行通過當前應用的運行時向運行環境所要總記憶體(totalMemory)和未被使用的記憶體(freeMemory)來計算出已經被使用的記憶體(usedMemory)。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GK2b-8.png" title="43.png" />
然後,它會在666行算出使用的記憶體佔據總記憶體的百分比數值(% *100),並且吧這個值存入dataset中,
然後668行初始化MeterPlot對象,這個對象代表了一個擁有指標的刻度盤,然後封裝了相應的資料。被JFreechart使用,它會顯示這個刻度面板的顏色,尺規等資訊。
然後第670行則會去建立一個JFreeChart對象,這個表徵圖的名字就是used-memory/total-memory的國際化文本:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GG015-9.png" title="44.png" />
並且吧MeterPlot中圖形的全部資訊plot傳入到JFreeChart對象中。
最後,第673行會建立一個圖片對象,然後插入到當前的頁面中:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GLV2-10.png" title="45.png" />
現在我們更加感興趣的是這個映像是如何建立的,名字在哪裡?位置在哪裡?
宏觀上看,它會調用ServletUtilities.saveChartASPNG()方法,吧jfreechart對象以及圖片的寬度高度都傳遞給這個方法,用於產生圖片。我們來看下實現:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GL557-11.png" title="46.png" />
首先,它會在180行去建立一個臨時目錄,這個臨時目錄在哪裡呢?我們看下createTempDir()的調用:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GIP2-12.png" title="47.png" />
現在明白了,原來臨時目錄在java.io.tmpdir中,而這個在我們伺服器上是
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GKa9-13.png" title="48.png" />
見java.io.tmpdir動態參數,所以我們知道這個臨時目錄建立在/app/Liferay/RI/liferay-portal-6.1.0-ce-ga1/tomcat-7.0.23/temp,也就是$CATALINA_TMP_DIR下:
然後我們在第183行擷取單次使用的圖片檔案的首碼是:jfreechart-onetime-
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GG295-14.png" title="49.png" />
然後在第185行,根據檔案的副檔名(png),首碼(prefix)來建立相應的圖片檔案的File對象:
我們驗證我們的$CATALINA_TMP_DIR,果然發現了一個圖片檔案被建立了:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GK310-15.png" title="50.png" />
但是其大小為0 ,這很正常,因為我們只建立了File對象,還沒有問其添加圖片內容。
新增內容的代碼是在第187行調用重載的ChartUtilities的saveChartAsPNG方法實現的:
可以發現,它先建立了一個FileOutputStream指向目標的圖片檔案,然後寫入這個檔案輸出資料流,最終是調用的通過JFreechart建立一個bufferedImage,然後利用EncoderUtil吧這個圖片編碼成png格式,並且最終寫入File對象對應的檔案輸出資料流中
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GK5B-16.png" title="51.png" />
現在我們對比這個圖片檔案,就發現它尺寸不再是0了現在是9253位元組):
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GK007-17.png" title="52.png" />
因為是一次性檔案,所以在第189行調用registryChartForDeletion方法註冊將這個圖片檔案刪除。
我們用瀏覽器的Web調試器看,果然這個資源檔被載入進來了:
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/111GL4S-18.png" title="53.png" />
最終會顯示在頁面上。
總結:
(1)在控制台中調用garbage collector去回收記憶體時,其本質是調用的當前Liferay應用對應的運行時Runtime的gc()方法,用於強制的進行一次記憶體回收。
(2)回收的結果會即時的反映到上方的儀錶盤中和資料區。這個儀錶盤是JFreechart畫的,它會從Runtime運行時中會去必要資訊,然後構建圖。然後JFreechart會在tomcat的臨時目錄建立一個臨時的png格式的檔案,開啟檔案輸出資料流執行該檔案,用JFreechart建立BufferedImage最後輸出到這個輸出資料流中,然後頁面上會以 src的形式載入這個新產生的圖片檔案並且顯示到頁面上。
(3)一旦執行完,因為這個臨時的圖片檔案PNG是一次性的,所以它會被架構從tomcat臨時目錄中移除。
本文出自 “平行線的凝聚” 部落格,請務必保留此出處http://supercharles888.blog.51cto.com/609344/1293853