1.影響一個(gè)系統(tǒng)性能的方方面面
一個(gè)web應(yīng)用不是一個(gè)孤立的個(gè)體,它是一個(gè)系統(tǒng)的部分,系統(tǒng)中的每一部分都會(huì)影響整個(gè)系統(tǒng)的性能

2.常用的性能評(píng)價(jià)/測(cè)試指標(biāo)
2.1 響應(yīng)時(shí)間
提交請(qǐng)求和返回該請(qǐng)求的響應(yīng)之間使用的時(shí)間,一般比較關(guān)注平均響應(yīng)時(shí)間。
常用操作的響應(yīng)時(shí)間列表:

2.2 并發(fā)數(shù)
同一時(shí)刻,對(duì)服務(wù)器有實(shí)際交互的請(qǐng)求數(shù)。
和網(wǎng)站在線用戶數(shù)的關(guān)聯(lián):1000個(gè)同時(shí)在線用戶數(shù),可以估計(jì)并發(fā)數(shù)在5%到15%之間,也就是同時(shí)并發(fā)數(shù)在50~150之間。
2.3 吞吐量
對(duì)單位時(shí)間內(nèi)完成的工作量(請(qǐng)求)的量度
2.4 關(guān)系
系統(tǒng)吞吐量和系統(tǒng)并發(fā)數(shù)以及響應(yīng)時(shí)間的關(guān)系:
理解為高速公路的通行狀況:
吞吐量是每天通過(guò)收費(fèi)站的車輛數(shù)目(可以換算成收費(fèi)站收取的高速費(fèi)),
并發(fā)數(shù)是高速公路上的正在行駛的車輛數(shù)目,
響應(yīng)時(shí)間是車速。
車輛很少時(shí),車速很快。但是收到的高速費(fèi)也相應(yīng)較少;隨著高速公路上車輛數(shù)目的增多,車速略受影響,但是收到的高速費(fèi)增加很快;
隨著車輛的繼續(xù)增加,車速變得越來(lái)越慢,高速公路越來(lái)越堵,收費(fèi)不增反降;
如果車流量繼續(xù)增加,超過(guò)某個(gè)極限后,任務(wù)偶然因素都會(huì)導(dǎo)致高速全部癱瘓,車走不動(dòng),當(dāng)然后也收不著,而高速公路成了停車場(chǎng)(資源耗盡)。

3.常用的性能優(yōu)化手段
3.1 總原則
3.1.1 避免過(guò)早優(yōu)化
不應(yīng)該把大量的時(shí)間耗費(fèi)在小的性能改進(jìn)上,過(guò)早考慮優(yōu)化是所有噩夢(mèng)的根源。
所以,我們應(yīng)該編寫清晰,直接,易讀和易理解的代碼,真正的優(yōu)化應(yīng)該留到以后,等到性能分析表明優(yōu)化措施有巨大的收益時(shí)再進(jìn)行。
但是過(guò)早優(yōu)化,不表示我們應(yīng)該編寫已經(jīng)知道的對(duì)性能不好的的代碼結(jié)構(gòu)。
3.1.2 進(jìn)行系統(tǒng)性能測(cè)試
所有的性能調(diào)優(yōu),都有應(yīng)該建立在性能測(cè)試的基礎(chǔ)上,直覺(jué)很重要,但是要用數(shù)據(jù)說(shuō)話,可以推測(cè),但是要通過(guò)測(cè)試求證。
3.1.3 尋找系統(tǒng)瓶頸,分而治之,逐步優(yōu)化
性能測(cè)試后,對(duì)整個(gè)請(qǐng)求經(jīng)歷的各個(gè)環(huán)節(jié)進(jìn)行分析,排查出現(xiàn)性能瓶頸的地方,定位問(wèn)題,分析影響性能的的主要因素是什么??jī)?nèi)存、磁盤IO、網(wǎng)絡(luò)、CPU,還是代碼問(wèn)題?架構(gòu)設(shè)計(jì)不足?或者確實(shí)是系統(tǒng)資源不足?
3.2 前端優(yōu)化常用手段
3.2.1 瀏覽器/App
減少請(qǐng)求數(shù);
合并CSS,Js,圖片
使用客戶端緩沖;
靜態(tài)資源文件緩存在瀏覽器中,有關(guān)的屬性Cache-Control和Expires
如果文件發(fā)生了變化,需要更新,則通過(guò)改變文件名來(lái)解決。
啟用壓縮
減少網(wǎng)絡(luò)傳輸量,但會(huì)給瀏覽器和服務(wù)器帶來(lái)性能的壓力,需要權(quán)衡使用。
資源文件加載順序
css放在頁(yè)面最上面,js放在最下面
減少****Cookie****傳輸
cookie包含在每次的請(qǐng)求和響應(yīng)中,因此哪些數(shù)據(jù)寫入cookie需要慎重考慮
給用戶一個(gè)提示
有時(shí)候在前端給用戶一個(gè)提示,就能收到良好的效果。畢竟用戶需要的是不要不理他。
3.2.2 CDN加速
CDN,又稱內(nèi)容分發(fā)網(wǎng)絡(luò),本質(zhì)仍然是一個(gè)緩存,而且是將數(shù)據(jù)緩存在用戶最近的地方。無(wú)法自行實(shí)現(xiàn)CDN的時(shí)候,可以考慮商用CDN服務(wù)。
3.2.3 反向代理緩存
將靜態(tài)資源文件緩存在反向代理服務(wù)器上,一般是Nginx。
3.2.4 WEB組件分離
將js,css和圖片文件放在不同的域名下??梢蕴岣邽g覽器在下載web組件的并發(fā)數(shù)。因?yàn)闉g覽器在下載同一個(gè)域名的的數(shù)據(jù)存在并發(fā)數(shù)限制。
3.3 應(yīng)用服務(wù)性能優(yōu)化
3.3.1 緩存
網(wǎng)站性能優(yōu)化第一定律:優(yōu)先考慮使用緩存優(yōu)化性能
緩存離用戶越近越好
緩存的基本原理和本質(zhì)
緩存是將數(shù)據(jù)存在訪問(wèn)速度較高的介質(zhì)中。可以減少數(shù)據(jù)訪問(wèn)的時(shí)間,同時(shí)避免重復(fù)計(jì)算。
合理使用緩沖的準(zhǔn)則
頻繁修改的數(shù)據(jù),盡量不要緩存,讀寫比2:1以上才有緩存的價(jià)值。
緩存一定是熱點(diǎn)數(shù)據(jù)。
應(yīng)用需要容忍一定時(shí)間的數(shù)據(jù)不一致。
緩存可用性問(wèn)題,一般通過(guò)熱備或者集群來(lái)解決。
緩存預(yù)熱,新啟動(dòng)的緩存系統(tǒng)沒(méi)有任何數(shù)據(jù),可以考慮將一些熱點(diǎn)數(shù)據(jù)提前加載到緩存系統(tǒng)。
解決緩存擊穿:
- 1、布隆過(guò)濾器
- 2、把不存在的數(shù)據(jù)也緩存起來(lái) ,比如有請(qǐng)求總是訪問(wèn)key = 23的數(shù)據(jù),但是這個(gè)key = 23的數(shù)據(jù)在系統(tǒng)中不存在,可以考慮在緩存中構(gòu)建一個(gè)( key=23 value = null)的數(shù)據(jù)。
分布式緩存
以集群的方式提供緩存服務(wù),有兩種實(shí)現(xiàn);
- 1、需要更新同步的分布式緩存,所有的服務(wù)器保存相同的緩存數(shù)據(jù),帶來(lái)的問(wèn)題就是,緩存的數(shù)據(jù)量受限制,其次,數(shù)據(jù)要在所有的機(jī)器上同步,代價(jià)很大。
- 2、每臺(tái)機(jī)器只緩存一部分?jǐn)?shù)據(jù),然后通過(guò)一定的算法選擇緩存服務(wù)器。常見(jiàn)的余數(shù)hash算法存在當(dāng)有服務(wù)器上下線的時(shí)候,大量緩存數(shù)據(jù)重建的問(wèn)題。所以提出了一致性哈希算法。
一致性哈希:
- 首先求出服務(wù)器(節(jié)點(diǎn))的哈希值,并將其配置到0~232的圓(continuum)上。
- 然后采用同樣的方法求出存儲(chǔ)數(shù)據(jù)的鍵的哈希值,并映射到相同的圓上。
- 然后從數(shù)據(jù)映射到的位置開(kāi)始順時(shí)針查找,將數(shù)據(jù)保存到找到的第一個(gè)服務(wù)器上。如果超過(guò)232仍然找不到服務(wù)器,就會(huì)保存到第一臺(tái)服務(wù)器上。
一致性哈希算法對(duì)于節(jié)點(diǎn)的增減都只需重定位環(huán)空間中的一小部分?jǐn)?shù)據(jù),具有較好的容錯(cuò)性和可擴(kuò)展性。
- 然后從數(shù)據(jù)映射到的位置開(kāi)始順時(shí)針查找,將數(shù)據(jù)保存到找到的第一個(gè)服務(wù)器上。如果超過(guò)232仍然找不到服務(wù)器,就會(huì)保存到第一臺(tái)服務(wù)器上。

一致性哈希算法在服務(wù)節(jié)點(diǎn)太少時(shí),容易因?yàn)楣?jié)點(diǎn)分部不均勻而造成數(shù)據(jù)傾斜問(wèn)題,此時(shí)必然造成大量數(shù)據(jù)集中到Node A上,而只有極少量會(huì)定位到Node B上。為了解決這種數(shù)據(jù)傾斜問(wèn)題,一致性哈希算法引入了虛擬節(jié)點(diǎn)機(jī)制,即對(duì)每一個(gè)服務(wù)節(jié)點(diǎn)計(jì)算多個(gè)哈希,每個(gè)計(jì)算結(jié)果位置都放置一個(gè)此服務(wù)節(jié)點(diǎn),稱為虛擬節(jié)點(diǎn)。具體做法可以在服務(wù)器ip或主機(jī)名的后面增加編號(hào)來(lái)實(shí)現(xiàn)。例如,可以為每臺(tái)服務(wù)器計(jì)算三個(gè)虛擬節(jié)點(diǎn),于是可以分別計(jì)算 “Node A#1”、“Node A#2”、“Node A#3”、“Node B#1”、“Node B#2”、“Node B#3”的哈希值,于是形成六個(gè)虛擬節(jié)點(diǎn):同時(shí)數(shù)據(jù)定位算法不變,只是多了一步虛擬節(jié)點(diǎn)到實(shí)際節(jié)點(diǎn)的映射,例如定位到“Node A#1”、“Node A#2”、“Node A#3”三個(gè)虛擬節(jié)點(diǎn)的數(shù)據(jù)均定位到Node A上。這樣就解決了服務(wù)節(jié)點(diǎn)少時(shí)數(shù)據(jù)傾斜的問(wèn)題。在實(shí)際應(yīng)用中,通常將虛擬節(jié)點(diǎn)數(shù)設(shè)置為32甚至更大,因此即使很少的服務(wù)節(jié)點(diǎn)也能做到相對(duì)均勻的數(shù)據(jù)分布。
3.3.2 異步
同步和異步,阻塞和非阻塞
同步和異步關(guān)注的是結(jié)果消息的通信機(jī)制
同步:同步的意思就是調(diào)用方需要主動(dòng)等待結(jié)果的返回
異步:異步的意思就是不需要主動(dòng)等待結(jié)果的返回,而是通過(guò)其他手段比如,狀態(tài)通知,回調(diào)函數(shù)等。
阻塞和非阻塞主要關(guān)注的是等待結(jié)果返回調(diào)用方的狀態(tài)
阻塞:是指結(jié)果返回之前,當(dāng)前線程被掛起,不做任何事
非阻塞:是指結(jié)果在返回之前,線程可以做一些其他事,不會(huì)被掛起。
- 1.同步阻塞:同步阻塞基本也是編程中最常見(jiàn)的模型,打個(gè)比方你去商店買衣服,你去了之后發(fā)現(xiàn)衣服賣完了,那你就在店里面一直等,期間不做任何事(包括看手機(jī)),等著商家進(jìn)貨,直到有貨為止,這個(gè)效率很低。jdk里的BIO就屬于 同步阻塞
- 2.同步非阻塞:同步非阻塞在編程中可以抽象為一個(gè)輪詢模式,你去了商店之后,發(fā)現(xiàn)衣服賣完了,這個(gè)時(shí)候不需要傻傻的等著,你可以去其他地方比如奶茶店,買杯水,但是你還是需要時(shí)不時(shí)的去商店問(wèn)老板新衣服到了嗎。jdk里的NIO就屬于 同步非阻塞
- 3.異步阻塞:異步阻塞這個(gè)編程里面用的較少,有點(diǎn)類似你寫了個(gè)線程池,submit然后馬上future.get(),這樣線程其實(shí)還是掛起的。有點(diǎn)像你去商店買衣服,這個(gè)時(shí)候發(fā)現(xiàn)衣服沒(méi)有了,這個(gè)時(shí)候你就給老板留給電話,說(shuō)衣服到了就給我打電話,然后你就守著這個(gè)電話,一直等著他響什么事也不做。這樣感覺(jué)的確有點(diǎn)傻,所以這個(gè)模式用得比較少。
- 4.異步非阻塞:好比你去商店買衣服,衣服沒(méi)了,你只需要給老板說(shuō)這是我的電話,衣服到了就打。然后你就隨心所欲的去玩,也不用操心衣服什么時(shí)候到,衣服一到,電話一響就可以去買衣服了。jdk里的AIO就屬于異步
常見(jiàn)異步的手段
- Servlet異步
servlet3中才有,支持的web容器在tomcat7和jetty8以后。 - 多線程
- 消息隊(duì)列
3.3.3 集群
可以很好的將用戶的請(qǐng)求分配到多個(gè)機(jī)器處理,對(duì)總體性能有很大的提升

3.3.4 程序
3.3.4.1 代碼級(jí)別
一個(gè)應(yīng)用的性能歸根結(jié)底取決于代碼是如何編寫的。
- 選擇合適的數(shù)據(jù)結(jié)構(gòu)
- 選擇更優(yōu)的算法
- 編寫更少的代碼
- 參考編寫高效優(yōu)雅的Java程序
3.3.4.2 并發(fā)編程
- 充分利用CPU多核,
- 實(shí)現(xiàn)線程安全的類,避免線程安全問(wèn)題
參考 JMM和底層實(shí)現(xiàn)原理
參考 JMM的思考 - 同步下減少鎖的競(jìng)爭(zhēng)
參考 并發(fā)安全
3.3.4.3 資源的復(fù)用
目的是減少開(kāi)銷很大的系統(tǒng)資源的創(chuàng)建和銷毀,比如數(shù)據(jù)庫(kù)連接,網(wǎng)絡(luò)通信連接,線程資源等等。
- 單例模式
- 池化技術(shù)
線程池、數(shù)據(jù)庫(kù)連接池
3.3.4.4 JVM
1)與JIT編譯器相關(guān)的優(yōu)化
對(duì)JVM性能影響最大的是編譯器。選擇編譯器是運(yùn)行java程序首先要做的選擇之一
1-1)熱點(diǎn)編譯的概念
對(duì)于程序來(lái)說(shuō),通常只有一部分代碼被經(jīng)常執(zhí)行,這些關(guān)鍵代碼被稱為應(yīng)用的熱點(diǎn),執(zhí)行的越多就認(rèn)為是越熱。將這些代碼編譯為本地機(jī)器特定的二進(jìn)制碼,可以有效提高應(yīng)用性能。
1-2)選擇編譯器類型
-server,更晚編譯,但是編譯后的優(yōu)化更多,性能更高
-client,很早就開(kāi)始編譯
-XX:+TieredCompilation,開(kāi)啟分層編譯,可以讓jvm在啟動(dòng)時(shí)啟用client編譯,隨著代碼變熱后再轉(zhuǎn)為server編譯。
缺省編譯器取決于機(jī)器位數(shù)、操作系統(tǒng)和CPU數(shù)目。32位的機(jī)器上,一般默認(rèn)都是client編譯,64位機(jī)器上一般都是server編譯,多核機(jī)器一般是server編譯。

圖片中的mix mode 一般指編譯時(shí)機(jī):
-Xint表示禁用JIT,所有字節(jié)碼都被解釋執(zhí)行,這個(gè)模式的速度最慢的。
-Xcomp表示所有字節(jié)碼都首先被編譯成本地代碼,然后再執(zhí)行。
-Xmixed,默認(rèn)模式,讓JIT根據(jù)程序運(yùn)行的情況,有選擇地將某些代碼編譯成本地代碼。
-Xcomp和-Xmixed到底誰(shuí)的速度快,針對(duì)不同的程序可能有不同的結(jié)果,基本還是推薦用默認(rèn)模式。
1-3)代碼緩存相關(guān)
在編譯后,會(huì)有一個(gè)代碼緩存保存編譯后的代碼,一旦這個(gè)緩存滿了,jvm將無(wú)法繼續(xù)編譯代碼。
當(dāng)jvm提示: CodeCache is full,就表示需要增加代碼緩存大小。
–XX:ReservedCodeCacheSize=N可以用來(lái)調(diào)整這個(gè)大小。

1-4)編譯閾值
代碼是否進(jìn)行編譯,取決于代碼執(zhí)行的頻度,是否到達(dá)編譯閾值。
計(jì)數(shù)器有兩種:方法調(diào)用計(jì)數(shù)器和方法里的循環(huán)回邊計(jì)數(shù)器
一個(gè)方法是否達(dá)到編譯閾值取決于方法中的兩種計(jì)數(shù)器之和。編譯閾值調(diào)整的參數(shù)為:-XX:CompileThreshold=N
方法調(diào)用計(jì)數(shù)器統(tǒng)計(jì)的并不是方法被調(diào)用的絕對(duì)次數(shù),而是一個(gè)相對(duì)的執(zhí)行頻率,即一段時(shí)間之內(nèi)方法被調(diào)用的次數(shù)。當(dāng)超過(guò)一定的時(shí)間限度,如果方法的調(diào)用次數(shù)仍然不足以讓它提交給即時(shí)編譯器編譯,那這個(gè)方法的調(diào)用計(jì)數(shù)器就會(huì)被減少一半,這個(gè)過(guò)程稱為方法調(diào)用計(jì)數(shù)器熱度的衰減(Counter Decay),而這段時(shí)間就稱為此方法統(tǒng)計(jì)的半衰周期(Counter Half Life Time)。進(jìn)行熱度衰減的動(dòng)作是在虛擬機(jī)進(jìn)行垃圾收集時(shí)順便進(jìn)行的,可以使用虛擬機(jī)參數(shù)-XX:-UseCounterDecay來(lái)關(guān)閉熱度衰減,讓方法計(jì)數(shù)器統(tǒng)計(jì)方法調(diào)用的絕對(duì)次數(shù),這樣,只要系統(tǒng)運(yùn)行時(shí)間足夠長(zhǎng),絕大部分方法都會(huì)被編譯成本地代碼。另外,可以使用-XX:CounterHalfLifeTime參數(shù)設(shè)置半衰周期的時(shí)間,單位是秒。
與方法計(jì)數(shù)器不同,回邊計(jì)數(shù)器沒(méi)有計(jì)數(shù)熱度衰減的過(guò)程,因此這個(gè)計(jì)數(shù)器統(tǒng)計(jì)的就是該方法循環(huán)執(zhí)行的絕對(duì)次數(shù)。
1-5)編譯線程
進(jìn)行代碼編譯的時(shí)候,是采用多線程進(jìn)行編譯的。
1-6)方法內(nèi)聯(lián)
內(nèi)聯(lián)默認(rèn)開(kāi)啟,-XX:-Inline,可以關(guān)閉,但是不要關(guān)閉,一旦關(guān)閉對(duì)性能有巨大影響。
方法是否內(nèi)聯(lián)取決于方法有多熱和方法的大小,
很熱的方法如果方法字節(jié)碼小于325字節(jié)才會(huì)內(nèi)聯(lián),這個(gè)大小由參數(shù) -XX:MaxFreqInlinesSzie=N 調(diào)整,但是這個(gè)很熱與熱點(diǎn)編譯不同,沒(méi)有任何參數(shù)可以調(diào)整熱度。
方法小于35個(gè)字節(jié)碼,一定會(huì)內(nèi)聯(lián),這個(gè)大小可以通過(guò)參數(shù)-XX:MaxInlinesSzie=N 調(diào)整。
1-7)逃逸分析
是JVM所做的最激進(jìn)的優(yōu)化,最好不要調(diào)整相關(guān)的參數(shù)。
2)GC調(diào)優(yōu)
參考 Java內(nèi)存區(qū)域
參考 Java垃圾回收器和內(nèi)存分配回收策略
2-1)目的
GC的時(shí)間夠小
GC的次數(shù)夠少
發(fā)生Full GC的周期足夠的長(zhǎng),時(shí)間合理,最好是不發(fā)生。
2-2)調(diào)優(yōu)的原則和步驟
1、 大多數(shù)的java應(yīng)用不需要GC調(diào)優(yōu)
2、 大部分需要GC調(diào)優(yōu)的的,不是參數(shù)問(wèn)題,是代碼問(wèn)題
3、 在實(shí)際使用中,分析GC情況優(yōu)化代碼比優(yōu)化GC參數(shù)要多得多;
4、 GC調(diào)優(yōu)是最后的手段
GC調(diào)優(yōu)的最重要的三個(gè)選項(xiàng):
第一位:選擇合適的GC回收器
第二位:選擇合適的堆大小
第三位:選擇年輕代在堆中的比重
步驟
- step1.監(jiān)控GC的狀態(tài)
使用各種JVM工具,查看當(dāng)前日志,分析當(dāng)前JVM參數(shù)設(shè)置,并且分析當(dāng)前堆內(nèi)存快照和gc日志,根據(jù)實(shí)際的各區(qū)域內(nèi)存劃分和GC執(zhí)行時(shí)間,覺(jué)得是否進(jìn)行優(yōu)化; - step2.分析結(jié)果,判斷是否需要優(yōu)化
如果各項(xiàng)參數(shù)設(shè)置合理,系統(tǒng)沒(méi)有超時(shí)日志出現(xiàn),GC頻率不高,GC耗時(shí)不高,那么沒(méi)有必要進(jìn)行GC優(yōu)化;如果GC時(shí)間超過(guò)1-3秒,或者頻繁GC,則必須優(yōu)化;
注意:如果滿足下面的指標(biāo),則一般不需要進(jìn)行GC:
Minor GC執(zhí)行時(shí)間不到50ms;
Minor GC執(zhí)行不頻繁,約10秒一次;
Full GC執(zhí)行時(shí)間不到1s;
Full GC執(zhí)行頻率不算頻繁,不低于10分鐘1次; - step3.調(diào)整GC類型和內(nèi)存分配
如果內(nèi)存分配過(guò)大或過(guò)小,或者采用的GC收集器比較慢,則應(yīng)該優(yōu)先調(diào)整這些參數(shù),并且先找1臺(tái)或幾臺(tái)機(jī)器進(jìn)行beta,然后比較優(yōu)化過(guò)的機(jī)器和沒(méi)有優(yōu)化的機(jī)器的性能對(duì)比,并有針對(duì)性的做出最后選擇; - step4.不斷的分析和調(diào)整
通過(guò)不斷的試驗(yàn)和試錯(cuò),分析并找到最合適的參數(shù) - step5.全面應(yīng)用參數(shù)
如果找到了最合適的參數(shù),則將這些參數(shù)應(yīng)用到所有服務(wù)器,并進(jìn)行后續(xù)跟蹤。
2-3)學(xué)會(huì)閱讀GC日志
以參數(shù)-Xms5m -Xmx5m -XX:+PrintGCDetails -XX:+UseSerialGC為例:
[DefNew: 1855K->1855K(1856K), 0.0000148 secs][Tenured: 2815K->4095K(4096K), 0.0134819 secs] 4671K
DefNew指明了收集器類型,而且說(shuō)明了收集發(fā)生在新生代。
1855K->1855K(1856K)表示,回收前 新生代占用1855K,回收后占用1855K,新生代大小1856K。
0.0000148 secs 表明新生代回收耗時(shí)。
Tenured表明收集發(fā)生在老年代
2815K->4095K(4096K), 0.0134819 secs:含義同新生代
最后的4671K指明堆的大小。
收集器參數(shù)變?yōu)?XX:+UseParNewGC,日志變?yōu)椋?br>
[ParNew: 1856K->1856K(1856K), 0.0000107 secs][Tenured: 2890K->4095K(4096K), 0.0121148 secs]
收集器參數(shù)變?yōu)?XX:+ UseParallelGC或UseParallelOldGC,日志變?yōu)椋?br>
[PSYoungGen: 1024K->1022K(1536K)] [ParOldGen: 3783K->3782K(4096K)] 4807K->4804K(5632K),
CMS收集器和G1收集器會(huì)有明顯的相關(guān)字樣
2-4)其他與GC相關(guān)的參數(shù)
調(diào)試跟蹤之 打印簡(jiǎn)單的GC信息 參數(shù): -verbose:gc, -XX:+PrintGC
打印詳細(xì)的GC信息 -XX:+PrintGCDetails, +XX:+PrintGCTimeStamps
-Xlogger:logpath 設(shè)置gc的日志路,如: -Xlogger:log/gc.log, 將gc.log的路徑設(shè)置到當(dāng)前目錄的log目錄下.
應(yīng)用場(chǎng)景: 將gc的日志獨(dú)立寫入日志文件,將GC日志與系統(tǒng)業(yè)務(wù)日志進(jìn)行了分離,方便開(kāi)發(fā)人員進(jìn)行追蹤分析。
-XX:+PrintHeapAtGC, 打印推信息
參數(shù)設(shè)置: -XX:+PrintHeapAtGC
應(yīng)用場(chǎng)景: 獲取Heap在每次垃圾回收前后的使用狀況
-XX:+TraceClassLoading
參數(shù)方法: -XX:+TraceClassLoading
應(yīng)用場(chǎng)景: 在系統(tǒng)控制臺(tái)信息中看到class加載的過(guò)程和具體的class信息,可用以分析類的加載順序以及是否可進(jìn)行精簡(jiǎn)操作。
-XX:+DisableExplicitGC禁止在運(yùn)行期顯式地調(diào)用System.gc()
-XX:-HeapDumpOnOutOfMemoryError 默認(rèn)關(guān)閉,建議開(kāi)啟,在java.lang.OutOfMemoryError 異常出現(xiàn)時(shí),輸出一個(gè)dump.core文件,記錄當(dāng)時(shí)的堆內(nèi)存快照。
-XX:HeapDumpPath=./java_pid<pid>.hprof 默認(rèn)是java進(jìn)程啟動(dòng)位置,用來(lái)設(shè)置堆內(nèi)存快照的存儲(chǔ)文件路徑。
2-5)推薦策略
- 年輕代大小選擇
- 響應(yīng)時(shí)間優(yōu)先的應(yīng)用:盡可能設(shè)大,直到接近系統(tǒng)的最低響應(yīng)時(shí)間限制(根據(jù)實(shí)際情況選擇).在此種情況下,年輕代收集發(fā)生的頻率也是最小的.同時(shí),減少到達(dá)年老代的對(duì)象.
- 吞吐量?jī)?yōu)先的應(yīng)用:盡可能的設(shè)置大,可能到達(dá)Gbit的程度.因?yàn)閷?duì)響應(yīng)時(shí)間沒(méi)有要求,垃圾收集可以并行進(jìn)行,一般適合8CPU以上的應(yīng)用.
- 避免設(shè)置過(guò)小.當(dāng)新生代設(shè)置過(guò)小時(shí)會(huì)導(dǎo)致:1.YGC次數(shù)更加頻繁 2.可能導(dǎo)致YGC對(duì)象直接進(jìn)入舊生代,如果此時(shí)舊生代滿了,會(huì)觸發(fā)FGC.
2.年老代大小選擇
- 響應(yīng)時(shí)間優(yōu)先的應(yīng)用:年老代使用并發(fā)收集器,所以其大小需要小心設(shè)置,一般要考慮并發(fā)會(huì)話率和會(huì)話持續(xù)時(shí)間等一些參數(shù).如果堆設(shè)置小了,可以會(huì)造成內(nèi)存碎 片,高回收頻率以及應(yīng)用暫停而使用傳統(tǒng)的標(biāo)記清除方式;如果堆大了,則需要較長(zhǎng)的收集時(shí)間.最優(yōu)化的方案,一般需要參考以下數(shù)據(jù)獲得: 并發(fā)垃圾收集信息、持久代并發(fā)收集次數(shù)、傳統(tǒng)GC信息、花在年輕代和年老代回收上的時(shí)間比例。
吞吐量?jī)?yōu)先的應(yīng)用:一般吞吐量?jī)?yōu)先的應(yīng)用都有一個(gè)很大的年輕代和一個(gè)較小的年老代.原因是,這樣可以盡可能回收掉大部分短期對(duì)象,減少中期的對(duì)象,而年老代盡存放長(zhǎng)期存活對(duì)象
3)調(diào)優(yōu)實(shí)戰(zhàn)
不同的內(nèi)存大小
不同的GC回收器
3.3 存儲(chǔ)性能優(yōu)化
3.3.1 盡量使用SSD
3.3.2 定時(shí)清理數(shù)據(jù)或者按數(shù)據(jù)的性質(zhì)分開(kāi)存放
3.3.3 結(jié)果集處理
用setFetchSize控制jdbc每次從數(shù)據(jù)庫(kù)中返回多少數(shù)據(jù)。
4 總結(jié)
調(diào)優(yōu)是個(gè)很復(fù)雜、很細(xì)致的過(guò)程,要根據(jù)實(shí)際情況調(diào)整,不同的機(jī)器、不同的應(yīng)用、不同的性能要求調(diào)優(yōu)的手段都是不同的。也沒(méi)有一個(gè)放之四海而皆準(zhǔn)的配置或者公式。比如說(shuō)性能有關(guān)的操作系統(tǒng)工具,和操作系統(tǒng)本身相關(guān)的所謂大頁(yè)機(jī)制,都需要大家平時(shí)去積累,去觀察,去實(shí)踐。
參考
- 1)享學(xué)課堂Mark老師筆記