1. 程式人生 > >JVM調優(三)程式程式碼調優

JVM調優(三)程式程式碼調優

根據第一節所講的基礎知識,我們根據線上不同的異常情況做程式的優化。

CPU佔用高

us高

根據之前的分析,CPU us高的原因主要是執行執行緒無任何掛起動作,且一直執行,導致CPU沒有機會去排程執行其他的執行緒,造成執行緒餓死的現象。對於這種情況,常見的一種優化方法是對這種執行緒的動作增加Thread.sleep,以釋放CPU的執行權,降低CPU的消耗。對於執行緒要不斷掃描某種狀態,達到自己的可繼續執行下去的條件時再執行(像程式碼while(xxx==yyy)),使用wait/notifyAll會比較好。

sy高

CPU sy高的原因主要是執行緒的執行狀態要經常切換,

另處一個原因是鎖競爭激烈,造成執行緒狀態切換。

方案:最簡單的優化方法是減少執行緒數。若系統要支援大量併發的話,最好建立執行緒佇列來緩解壓力。

注意:降低執行緒數後,可能造成sy降低,us升高。

若無法降低執行緒數,可採用協程,以支援更高併發量。粒度上協程比執行緒小,執行緒不用頻繁切換。(協程在java裡還不太成熟,但是可以大膽往這方面嘗試。)

檔案IO消耗嚴重

從程式角度而言,造成檔案IO消耗嚴重的原因主要是多個執行緒將大量的資料寫到同一檔案,導致檔案很快變得很大,從而寫入速度越來越慢,並造成各執行緒激烈爭搶檔案鎖。

方案:

非同步寫檔案,避免寫入慢導致應用效能下降太多。(如日誌採用log4j的AsyncAppender)

批量讀寫

限流,將讀寫IO降低到一個能接受的範圍。(時間窗,停牌桶等)。

限制檔案大小,大檔案讀或者追加寫動作會增加耗時,限制檔案大小後,超過一定值新生成檔案。

網路IO消耗

方案:限流,控制傳送頻次。

記憶體消耗

釋放不必要的引用。典型如ThreadLocal,線上程結束時,這裡面的內容不會主動釋放,會造成記憶體增大。檢視!ThreadLocal使用不當後果

使用物件快取池建立物件的例項要耗費一定的CPU以及記憶體,使用物件快取池一定程度上可降低JVM Heap記憶體的使用。(慎用,使用不當會造成記憶體增大)。但是引入合理的快取失效機制,會改善記憶體佔用。如FIFO,LRU,LFU。

LRU是最近最少使用頁面置換演算法(Least Recently Used),也就是首先淘汰最長時間未被使用的頁面。LFU是最近最不常用頁面置換演算法(Least Frequently Used),也就是淘汰一定時期內被訪問次數最少的頁。

合理使用SoftReference和WeakReference對於佔據記憶體但又不是必須存在的物件,例如快取物件,也可以基於SoftReference或WeakReference的方式來進行快取。