程式者的胡言亂語
找出Java程式吃掉CPU的元兇
Java應用程式的效能問題大致上以三種為主:執行的太慢、佔據太多的CPU時間、佔用太多的記憶體。執行的太慢不一定會佔去太多的CPU時間,因為執行的慢,有可能是因為I/O動作所導致的。而佔去太多的CPU時間有可能讓系統變慢,但不一定會引發明顯變慢的感覺,因為大多數的程式都不那麼需要CPU。
之前曾提到Busy Loop,就是在loop裡做了CPU intensive的活動,導致程式佔用極多的CPU時間,時常都是9x%以上。這就是一個佔去太多CPU時間的例子。
前幾天我們試著要解決一個上線系統的效能問題。這個系統並沒有表現出反應時間太慢的情況,但CPU使用率持續高居不下,所以得試著加以解決。
我們手邊沒有什麼效能量測或調校的工具,所以只好試著土法煉鋼。其實效能調校的程序都很固定:
步驟1:進行效能量測,也就是profiling
步驟2:找出效能瓶頸
步驟3:針對效能瓶頸進行改善
步驟4:回到步驟1,重覆這個程序,直到沒有明顯的效能瓶頸為止
很明顯的,我們會需要一個量測的工具。你可以記錄每一段程式碼的執行起迄時間點,但那只能用來知道總共的執行時間,卻不能知道在這段時間內,這段程式碼真正被分配到的CPU時間有多少。為此,我們得有個工具才行。
我找到一篇文章:”Profiling CPU usage from within a Java application”,在這篇文章中,利用JNI使用Wi32既有的API來取得程式執行的CPU時間。由於我們的平台恰好就在Win32上,所以直接使用在這篇文章中開發的程式庫。
接下來就只要量測各個執行點究竟佔用了CPU使用率就可以了。
final SystemInformation.CPUUsageSnapshot s1 = SystemInformation.makeCPUUsageSnapshot(); final SystemInformation.CPUUsageSnapshot s2 = SystemInformation.makeCPUUsageSnapshot(); double d = SystemInformation.getProcessCPUUsage(s1, s2); |
它提供多個classes,但其實只要SystemInformation這個class就可以了。如果要量測在你的程式中的兩個執行點之間共佔用了多少CPU使用率,只要分別在這兩個執行點上照一份快照(makeCPUUsageSnapshot()),接著使用getProcessCPUUsage()就可以算出在這兩個執行點之間,共佔用了多少百分比的CPU使用率。
安置拍照的地點是一個需要注意的事項。由於你不那麼明確知道元兇究竟在何處,所以在第一輪安置拍照點時,拍照點總共涵蓋的範圍會很廣,但間隔卻很大。但第一輪洗出照片後,你會知道元兇究竟落在那兩個點之間,接著再進行第二輪,在找出的兩點之間,再安置更細的拍照點,依此遞迴下去,最終就會找到元兇,基本上這就像是binary search的方式。
其實效能瓶頸的位置,往往有時叫人驚訝,我們找到的地方竟然是一段使用JAAS的程式碼。透過一些caching的技巧,這個瓶頸就解除了。原本CPU使用率時常高居在70%-99%的系統,立即降到1%以下。
所以我覺得這個程式庫其實滿適合窮人使用的-當你買不起昂貴的效能量測工具時,土法煉鋼也不錯。
這個程式庫也沒有什麼內容,主要就是利用GetProcessTimes()這個Win
Posted at 08:01下午 十一月 03, 2006 by Chien-Hsing Wang in Java | 迴響[0]
星期五 十一月 03, 2006
