JVM調優(最關鍵參數爲:-Xms -Xmx -Xmn -XX:SurvivorRatio -XX:MaxTenuringThreshold)算法
代大小調優:數據庫
避免新生代大小設置太小、避免新生代大小設置過大、避免Survivor設置太小或過大、合理設置新生代存活週期。緩存
-Xmn 調整新生代大小,新生代越大一般也意味着更多對象會在minor GC階段被回收,但可能有可能形成舊生代大小,形成頻繁觸發Full GC,甚至是OutOfMemoryError。網絡
-XX:SurvivorRatio調整Eden區與Survivor區的大小,Eden 區越大一般也意味着minor GC發生頻率越低,但可能有可能形成Survivor區過小,致使對象minor GC後就直接進入舊生代,從而更頻繁觸發Full GC。多線程
GC策略的調優:CMS GC多數動做是和應用併發進行的,確實能夠減少GC動做給應用形成的暫停時間。對於Web應用很是須要一個對應用形成暫停時間短的GC,再加上Web應用 的瓶頸都不在CPU上,在G1還不夠成熟的狀況下,CMS GC是不錯的選擇。併發
(若是系統不是CPU密集型,且重新生代進入舊生代的大部分對象是能夠回收的,那麼採用CMS GC能夠更好地在舊生代滿以前完成對象的回收,更大程度下降Full GC發生的可能)框架
在調整了內存管理方面的參數後應經過-XX:PrintGCDetails、-XX:+PrintGCTimeStamps、 -XX:+PrintGCApplicationStoppedTime以及jstat或visualvm等方式觀察調整後的GC情況。異步
出內存管理之外的其餘方面的調優參數:-XX:CompileThreshold、-XX:+UseFastAccessorMethods、 -XX:+UseBaiasedLocking。分佈式
程序調優 ide
CPU消耗嚴重的解決方法
CPU us高的解決方法:
CPU us 高的緣由主要是執行線程不須要任何掛起動做,且一直執行,致使CPU 沒有機會去調度執行其餘的線程。
調優方案: 增長Thread.sleep,以釋放CPU 的執行權,下降CPU 的消耗。以損失單次執行性能爲代價的,但因爲其下降了CPU 的消耗,對於多線程的應用而言,反而提升了整體的平均性能。
(在實際的Java應用中相似場景, 對於這種場景最佳方式是改成採用wait/notify機制)
對於其餘相似循環次數過多、正則、計算等形成CPU us太高的情況, 則須要結合業務調優。
對於GC頻繁,則須要經過JVM調優或程序調優,下降GC的執行次數。
CPU sy高的解決方法:
CPU sy 高的緣由主要是線程的運行狀態要常常切換,對於這種狀況,常見的一種優化方法是減小線程數。
調優方案: 將線程數下降
這種調優事後有可能會形成CPU us太高,因此合理設置線程數很是關鍵。
對於Java分佈式應用,還有一種典型現象是應用中有較多的網絡IO操做和確實須要一些鎖競爭機制(如數據庫鏈接池),但爲了可以支撐搞得併發量,可採用協程(Coroutine)來支撐更高的併發量,避免併發量上漲後形成CPU sy消耗嚴重、系統load迅速上漲和系統性能降低。
在Java中實現協程的框架有Kilim,Kilim執行一項任務建立Task,使用Task的暫停機制,而不是Thread,Kilim承擔了線程調度以及上下切換動做,Task相對於原生Thread而言就輕量級多了,且能更好利用CPU。Kilim帶來的是線程使用率的提高,但同時因爲要在JVM堆中保存Task上下文信息,所以在採用Kilim的狀況下要消耗更多的內存。(目前JDK 7中也有一個支持協程方式的實現,另外基於JVM的Scala的Actor也可用於在Java使用協程)
文件IO消耗嚴重的解決方法
從程序的角度而言,形成文件IO消耗嚴重的緣由主要是多個線程在寫進行大量的數據到同一文件,致使文件很快變得很大,從而寫入速度愈來愈慢,並形成各線程激烈爭搶文件鎖。
經常使用調優方法:
異步寫文件
批量讀寫
限流
限制文件大小
內存消耗嚴重的解決方法
釋放沒必要要的引用:代碼持有了不須要的對象引用,形成這些對象沒法被GC,從而佔據了JVM堆內存。(使用ThreadLocal:注意在線程內動做執行完畢時,需執行ThreadLocal.set把對象清除,避免持有沒必要要的對象引用)
使用對象緩存池:建立對象要消耗必定的CPU以及內存,使用對象緩存池必定程度上可下降JVM堆內存的使用。
採用合理的緩存失效算法:若是放入太多對象在緩存池中,反而會形成內存的嚴重消耗, 同時因爲緩存池一直對這些對象持有引用,從而形成Full GC增多,對於這種情況要合理控制緩存池的大小,避免緩存池的對象數量無限上漲。(經典的緩存失效算法來清除緩存池中的對象:FIFO、LRU、LFU等)
合理使用SoftReference和WeekReference:SoftReference的對象會在內存不夠用的時候回收,WeekReference的對象會在Full GC的時候回收。
資源消耗很少但程序執行慢的狀況的解決方法
下降鎖競爭: 多線多了,鎖競爭的情況會比較明顯,這時候線程很容易處於等待鎖的情況,從而致使性能降低以及CPU sy上升。
使用併發包中的類:大多數採用了lock-free、nonblocking算法。
使用Treiber算法:基於CAS以及AtomicReference。
使用Michael-Scott非阻塞隊列算法:基於CAS以及AtomicReference,典型ConcurrentLindkedQueue。
(基於CAS和AtomicReference來實現無阻塞是不錯的選擇,但值得注意的是,lock-free算法需不斷的循環比較來保證資源的一致性的,對於衝突較多的應用場景而言,會帶來更高的CPU消耗,所以不必定採用CAS實現無阻塞的就必定比採用lock方式的性能好。 還有一些無阻塞算法的改進:MCAS、WSTM等)
儘量少用鎖:儘量只對須要控制的資源作加鎖操做(一般沒有必要對整個方法加鎖,儘量讓鎖最小化,只對互斥及原子操做的地方加鎖,加鎖時儘量以保護資源的最小化粒度爲單位--如只對須要保護的資源加鎖而不是this)。
拆分鎖:獨佔鎖拆分爲多把鎖(讀寫鎖拆分、相似ConcurrentHashMap中默認拆分爲16把鎖),不少程度上能提升讀寫的性能,但須要注意在採用拆分鎖後,全局性質的操做會變得比較複雜(如ConcurrentHashMap中size操做)。(拆分鎖太多也會形成反作用,如CPU消耗明顯增長)
去除讀寫操做的互斥:在修改時加鎖,並複製對象進行修改,修改完畢後切換對象的引用,從而讀取時則不加鎖。這種稱爲CopyOnWrite,CopyOnWriteArrayList是典型實現,好處是能夠明顯提高讀的性能,適合讀多寫少的場景, 但因爲寫操做每次都要複製一份對象,會消耗更多的內存。