《深圳尚學(xué)堂Java培訓(xùn):Java程序性能調(diào)優(yōu)步驟(二)》要點(diǎn):
本文介紹了深圳尚學(xué)堂Java培訓(xùn):Java程序性能調(diào)優(yōu)步驟(二),希望對(duì)您有用。如果有疑問(wèn),可以聯(lián)系我們。
3、性能調(diào)優(yōu)
3.1JVM調(diào)優(yōu)
3.1.1、代大小調(diào)優(yōu)
① 避免新生代大小設(shè)置過(guò)小
1、避免頻繁進(jìn)行minor GC;2、可能導(dǎo)致minor GC對(duì)象直接進(jìn)入舊生代,占據(jù)舊生代空間,觸發(fā)FULL GC.
② 避免新生代設(shè)置過(guò)大
1、導(dǎo)致舊生代變小,可能導(dǎo)致FULL GC頻繁執(zhí)行;2、導(dǎo)致minor GC的耗時(shí)大幅度增加.
③ 避免survivor space過(guò)小或者過(guò)大
④ 根據(jù)具體代碼合理設(shè)置新生代的存活周期.
3.2.1、GC策略調(diào)優(yōu)
串行GC性能太差,因此實(shí)際應(yīng)用時(shí)主要是應(yīng)用并行和并發(fā)GC,大部分Web應(yīng)用在處理哀求時(shí)設(shè)置了一個(gè)最大可同時(shí)處理的哀求數(shù),當(dāng)超出此哀求數(shù)時(shí),會(huì)將之后的哀求放 入等待隊(duì)列中,而這個(gè)等待隊(duì)列也限制了大小.當(dāng)?shù)却?duì)列滿(mǎn)了后,仍然有哀求進(jìn)入,那么這些哀求將丟棄,所有的哀求又都是有超時(shí)限制度.
在這種情況下如果觸發(fā)了FULL GC造成應(yīng)用暫停時(shí)間較長(zhǎng)的FULL GC,則有可能等這次FULL GC之后,應(yīng)用中很多哀求就超時(shí)或者被丟棄了.
從上面可以看出,Web應(yīng)用非常需要一個(gè)對(duì)應(yīng)用造成暫停時(shí)間較短的GC,再加上大部分Web應(yīng)用的瓶頸都不在CPU上.因此對(duì)于Web應(yīng)用而言,在G1還不夠成熟的情況下,CMS GC是不錯(cuò)的選擇.
3.2、程序調(diào)優(yōu)
3.2.1、CPU us高的解決辦法
① 執(zhí)行線(xiàn)程無(wú)任何掛起動(dòng)作,且一直運(yùn)行,導(dǎo)致CPU沒(méi)有機(jī)會(huì)去調(diào)度執(zhí)行其他的線(xiàn)程,造成線(xiàn)程餓死的現(xiàn)象.
解決:對(duì)這種線(xiàn)程的動(dòng)作增加Thread.sleep(int),以釋放CPU的執(zhí)行權(quán),降低CPU的消耗.
原理:以損失單次執(zhí)行性能為代價(jià),但由于降低了CPU消耗,在多線(xiàn)程的情況下,反而提高了平均性能.
② 狀態(tài)掃描.如:某線(xiàn)程要等其他線(xiàn)程改變了值才可以繼續(xù)執(zhí)行.
解決:改為采用wait/notify機(jī)制.
③ 循環(huán)次數(shù)過(guò)多、正則、計(jì)算等造成CPU us過(guò)高的情況.結(jié)合業(yè)務(wù)需求進(jìn)行調(diào)優(yōu).code review是王道.
④ 頻繁GC造成us高的情況,通過(guò)JVM調(diào)優(yōu)或程序調(diào)優(yōu),降低GC的執(zhí)行次數(shù).
3.2.2、CPU sy高的解決辦法
① 線(xiàn)程運(yùn)行狀態(tài)經(jīng)常切換
解決:減少線(xiàn)程數(shù),且使用線(xiàn)程池
② 線(xiàn)程之間鎖競(jìng)爭(zhēng)激烈
解決:盡可能降低鎖的競(jìng)爭(zhēng).
1、使用并發(fā)包中的類(lèi)(java.util.concurrent.*)
2、使用Treiber算法
3、使用Michael-Scott非阻塞隊(duì)列算法(ConcurrentLinkedQueue就是典型的該算法的非阻塞隊(duì)列)
4、通常沒(méi)必要對(duì)整個(gè)辦法加鎖,只對(duì)需要控制資源的地方做加鎖操作.
5、拆分鎖,把獨(dú)占鎖拆分為多把鎖,如:ConcurrentHashMap.很大程度上可以提高讀寫(xiě)速度.
6、去除讀寫(xiě)操作的互斥鎖
③ 較多網(wǎng)絡(luò)IO操作或者確實(shí)需要一些鎖競(jìng)爭(zhēng)機(jī)制(如數(shù)據(jù)庫(kù)連接池),但為了能夠支持高的并發(fā)量,在Java應(yīng)用中又只能借助更多的線(xiàn)程來(lái)支撐.
解決:采用協(xié)程(Coroutine)來(lái)支持更高的并發(fā)量,避免并發(fā)量上漲之后造成CPU sy消耗嚴(yán)重、系統(tǒng)load迅速上漲和系統(tǒng)性能下降.
Java中目前主要可用于實(shí)現(xiàn)協(xié)程的框架為Kilim,早使用Kilim執(zhí)行一項(xiàng)任務(wù),并不創(chuàng)建Thread,而是采用Task.
3.3、文件IO消耗嚴(yán)重的解決辦法
從程序角度看,造成文件IO消耗嚴(yán)重的原因主要是多個(gè)線(xiàn)程在寫(xiě)大量的數(shù)據(jù)到同一文件.導(dǎo)致文件很快變大.
從而寫(xiě)入速度越來(lái)越慢,并造成各線(xiàn)程激烈爭(zhēng)搶文件鎖,對(duì)于這種情況解決辦法:
1、異步寫(xiě)入文件;2、批量讀寫(xiě);3、限流;4、限制文件大小;5、盡可能采用緩沖區(qū)等方式來(lái)讀取文件內(nèi)容
3.4、網(wǎng)絡(luò)IO消耗嚴(yán)重的解決辦法
從程序角度而言,造成網(wǎng)絡(luò)IO消耗嚴(yán)重的主要原因是同時(shí)需要發(fā)送或接受的包太多.可采用限流.限流通常是限制發(fā)送packet的頻率,從而在網(wǎng)絡(luò)IO消耗可接受的情況下來(lái)發(fā)送packet.
3.5、內(nèi)存消耗嚴(yán)重的情況
1、對(duì)JVM調(diào)優(yōu);2、代碼調(diào)優(yōu);
代碼調(diào)優(yōu)的方式:
① 釋放不必要的引用.如使用ThreadLocal,由于線(xiàn)程復(fù)用,ThreadLocal中存放的對(duì)象如未主動(dòng)釋放的話(huà),不會(huì)被GC.應(yīng)該在執(zhí)行完畢執(zhí)行ThreadLocal.set把對(duì)象清除,避免此有不必要的對(duì)象引用.
② 使用對(duì)象緩存池(享元模式)
③ 采用合理的緩存失效算法(FIFO、LRU、LFU等)
當(dāng)緩存池達(dá)到最大容量后,如果再加入新對(duì)象時(shí)采用FIFO、LRU、LFU等失效算法.
④ 對(duì)于占據(jù)內(nèi)存但又不是必須存在的對(duì)象使用SoftReference、WeakReference的方式進(jìn)行緩存.
SoftReference在內(nèi)存不夠用的情況進(jìn)行回收;WeakReference在FULL GC的情況下進(jìn)行回收.
3.6、對(duì)于資源消耗不多,但程序執(zhí)行慢的情況
3.6.1、鎖競(jìng)爭(zhēng)激烈—見(jiàn)3.2.2②
3.6.2、未充分利用硬件資源.
① 未充分利用CPU
啟動(dòng)多線(xiàn)程,但是單線(xiàn)程演變?yōu)槎嗑€(xiàn)程要加鎖,如:?jiǎn)尉€(xiàn)程計(jì)算,拆分為多線(xiàn)程分別計(jì)算,最后合并結(jié)果 如:JDK7的fork-join框架.
② 未充分使用內(nèi)存
數(shù)據(jù)庫(kù)緩存、耗時(shí)資源緩存(數(shù)據(jù)庫(kù)連接的創(chuàng)建、網(wǎng)絡(luò)連接的創(chuàng)建等)、頁(yè)面片段的緩存等.
結(jié)束語(yǔ):從純粹的軟件角度調(diào)優(yōu)來(lái)講,充分而不過(guò)分的使用硬件資源,合理調(diào)整JVM以及合理使用JDK包是調(diào)優(yōu)的三大有效原則,調(diào)優(yōu)沒(méi)有“銀彈”.結(jié)合系統(tǒng)現(xiàn)狀和多嘗試不同的調(diào)優(yōu)策略是找到合適調(diào)優(yōu)辦法的唯一途徑.
《深圳尚學(xué)堂Java培訓(xùn):Java程序性能調(diào)優(yōu)步驟(二)》是否對(duì)您有啟發(fā),歡迎查看更多與《深圳尚學(xué)堂Java培訓(xùn):Java程序性能調(diào)優(yōu)步驟(二)》相關(guān)教程,學(xué)精學(xué)透。維易PHP學(xué)院為您提供精彩教程。
轉(zhuǎn)載請(qǐng)注明本頁(yè)網(wǎng)址:
http://www.fzlkiss.com/jiaocheng/8692.html