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的方式來進行緩存。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章