一绍哎、JVM參數(shù)配置
1来农、常見(jiàn)參數(shù)配置
- -XX:+PrintGC 每次觸發(fā)GC的時(shí)候打印相關(guān)日志
- -XX:+UseSerialGC 串行回收
- -XX:+PrintGCDetails 更詳細(xì)的GC日志
- -Xms 堆初始值
- -Xmx 堆最大可用值
- -Xmn 新生代堆最大可用值
- -XX:SurvivorRatio 用來(lái)設(shè)置新生代中eden空間和from/to空間的比例.
- -XX:NewRatio 配置新生代與老年代占比 1:2
- 含以-XX:SurvivorRatio=eden/from=den/to
總結(jié):在實(shí)際工作中鞋真,我們可以直接將初始的堆大小與最大堆大小相等,
這樣的好處是可以減少程序運(yùn)行時(shí)垃圾回收次數(shù)沃于,從而提高效率涩咖。
-XX:SurvivorRatio 用來(lái)設(shè)置新生代中eden空間和from/to空間的比例.
2、堆內(nèi)存大小配置
使用示例: -Xmx20m -Xms5m
說(shuō)明: 當(dāng)下Java應(yīng)用最大可用內(nèi)存為20M繁莹, 初始內(nèi)存為5M
byte[] b = new byte[4 * 1024 * 1024];
System.out.println("分配了4M空間給數(shù)組");
System.out.print("最大內(nèi)存");
System.out.println(Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M");
System.out.print("可用內(nèi)存");
System.out.println(Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M");
System.out.print("已經(jīng)使用內(nèi)存");
System.out.println(Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");
3檩互、設(shè)置新生代比例參數(shù)
使用示例:-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
說(shuō)明:堆內(nèi)存初始化值20m,堆內(nèi)存最大值20m,新生代最大值可用1m咨演,eden空間和from/to空間的比例為2/1
byte[] b = null;
for (int i = 0; i < 10; i++) {
b = new byte[1 * 1024 * 1024];
}
4闸昨、設(shè)置新生代與老年代比例參數(shù)
使用示例: -Xms20m -Xmx20m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC
-XX:NewRatio=2
說(shuō)明:堆內(nèi)存初始化值20m,堆內(nèi)存最大值20m,新生代最大值可用1m薄风,eden空間和from/to空間的比例為2/1
新生代和老年代的占比為1/2
二饵较、實(shí)戰(zhàn)OutOfMemoryError異常
1、Java堆溢出
錯(cuò)誤原因: java.lang.OutOfMemoryError: Java heap space 堆內(nèi)存溢出
解決辦法:設(shè)置堆內(nèi)存大小 // -Xms1m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
// -Xms1m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
List<Object> listObject = new ArrayList<>();
for (int i = 0; i < 10; i++) {
System.out.println("i:" + i);
Byte[] bytes = new Byte[1 * 1024 * 1024];
listObject.add(bytes);
}
System.out.println("添加成功...");
2遭赂、虛擬機(jī)棧溢出
錯(cuò)誤原因: java.lang.StackOverflowError 棧內(nèi)存溢出
棧溢出 產(chǎn)生于遞歸調(diào)用循诉,循環(huán)遍歷是不會(huì)的,但是循環(huán)方法里面產(chǎn)生遞歸調(diào)用撇他, 也會(huì)發(fā)生棧溢出茄猫。
解決辦法:設(shè)置線程最大調(diào)用深度
-Xss5m 設(shè)置最大調(diào)用深度
public class JvmDemo04 {
private static int count;
public static void count(){
try {
count++;
count();
} catch (Throwable e) {
System.out.println("最大深度:"+count);
e.printStackTrace();
}
}
public static void main(String[] args) {
count();
}
}
3、內(nèi)存溢出與內(nèi)存泄漏區(qū)別
Java內(nèi)存泄漏就是沒(méi)有及時(shí)清理內(nèi)存垃圾困肩,導(dǎo)致系統(tǒng)無(wú)法再給你提供內(nèi)存資源(內(nèi)存資源耗盡)划纽;
而Java內(nèi)存溢出就是你要求分配的內(nèi)存超出了系統(tǒng)能給你的,系統(tǒng)不能滿足需求锌畸,于是產(chǎn)生溢出勇劣。
內(nèi)存溢出,這個(gè)好理解蹋绽,說(shuō)明存儲(chǔ)空間不夠大芭毙。就像倒水倒多了,從杯子上面溢出了來(lái)了一樣卸耘。
內(nèi)存泄漏退敦,原理是,使用過(guò)的內(nèi)存空間沒(méi)有被及時(shí)釋放蚣抗,長(zhǎng)時(shí)間占用內(nèi)存侈百,最終導(dǎo)致內(nèi)存空間不足瓮下,而出現(xiàn)內(nèi)存溢出。
三钝域、垃圾收集器
1讽坏、串行與并行收集器
串行回收: JDK1.5前的默認(rèn)算法 缺點(diǎn)是只有一個(gè)線程,執(zhí)行垃圾回收時(shí)程序停止的時(shí)間比較長(zhǎng)
并行回收: 多個(gè)線程執(zhí)行垃圾回收適合于吞吐量的系統(tǒng)例证,回收時(shí)系統(tǒng)會(huì)停止運(yùn)行
2路呜、serial收集器
串行收集器是最古老,最穩(wěn)定以及效率高的收集器织咧,可能會(huì)產(chǎn)生較長(zhǎng)的停頓胀葱,只使用一個(gè)線程去回收。新生代笙蒙、老年代使用串行回收抵屿;新生代復(fù)制算法、老年代標(biāo)記-壓縮捅位;垃圾收集的過(guò)程中會(huì)Stop The World(服務(wù)暫停)
一個(gè)單線程的收集器轧葛,在進(jìn)行垃圾收集時(shí)候,必須暫停其他所有的工作線程直到它收集結(jié)束艇搀。
特點(diǎn):CPU利用率最高尿扯,停頓時(shí)間即用戶等待時(shí)間比較長(zhǎng)。
適用場(chǎng)景:小型應(yīng)用
通過(guò)JVM參數(shù)-XX:+UseSerialGC可以使用串行垃圾回收器中符。
3姜胖、ParNew收集器
ParNew收集器其實(shí)就是Serial收集器的多線程版本。新生代并行淀散,老年代串行右莱;新生代復(fù)制算法、老年代標(biāo)記-壓縮
參數(shù)控制:-XX:+UseParNewGC ParNew收集器
-XX:ParallelGCThreads 限制線程數(shù)量
4档插、parallel 收集器
Parallel Scavenge收集器類(lèi)似ParNew收集器慢蜓,Parallel收集器更關(guān)注系統(tǒng)的吞吐量」牛可以通過(guò)參數(shù)來(lái)打開(kāi)自適應(yīng)調(diào)節(jié)策略晨抡,虛擬機(jī)會(huì)根據(jù)當(dāng)前系統(tǒng)的運(yùn)行情況收集性能監(jiān)控信息,動(dòng)態(tài)調(diào)整這些參數(shù)以提供最合適的停頓時(shí)間或最大的吞吐量则剃;也可以通過(guò)參數(shù)控制GC的時(shí)間不大于多少毫秒或者比例耘柱;新生代復(fù)制算法、老年代標(biāo)記-壓縮
采用多線程來(lái)通過(guò)掃描并壓縮堆
特點(diǎn):停頓時(shí)間短棍现,回收效率高调煎,對(duì)吞吐量要求高。
適用場(chǎng)景:大型應(yīng)用己肮,科學(xué)計(jì)算士袄,大規(guī)模數(shù)據(jù)采集等悲关。
通過(guò)JVM參數(shù) XX:+USeParNewGC 打開(kāi)并發(fā)標(biāo)記掃描垃圾回收器。
5娄柳、cms收集器
CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時(shí)間為目標(biāo)的收集器寓辱。目前很大一部分的Java應(yīng)用都集中在互聯(lián)網(wǎng)站或B/S系統(tǒng)的服務(wù)端上,這類(lèi)應(yīng)用尤其重視服務(wù)的響應(yīng)速度赤拒,希望系統(tǒng)停頓時(shí)間最短秫筏,以給用戶帶來(lái)較好的體驗(yàn)。
從名字(包含“Mark Sweep”)上就可以看出CMS收集器是基于“標(biāo)記-清除”算法實(shí)現(xiàn)的需了,它的運(yùn)作過(guò)程相對(duì)于前面幾種收集器來(lái)說(shuō)要更復(fù)雜一些跳昼,整個(gè)過(guò)程分為4個(gè)步驟般甲,包括:
- 初始標(biāo)記(CMS initial mark)
- 并發(fā)標(biāo)記(CMS concurrent mark)
- 重新標(biāo)記(CMS remark)
- 并發(fā)清除(CMS concurrent sweep)
其中初始標(biāo)記肋乍、重新標(biāo)記這兩個(gè)步驟仍然需要“Stop The World”。初始標(biāo)記僅僅只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象敷存,速度很快墓造,并發(fā)標(biāo)記階段就是進(jìn)行GC Roots Tracing的過(guò)程,而重新標(biāo)記階段則是為了修正并發(fā)標(biāo)記期間锚烦,因用戶程序繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記錄觅闽,這個(gè)階段的停頓時(shí)間一般會(huì)比初始標(biāo)記階段稍長(zhǎng)一些,但遠(yuǎn)比并發(fā)標(biāo)記的時(shí)間短涮俄。
由于整個(gè)過(guò)程中耗時(shí)最長(zhǎng)的并發(fā)標(biāo)記和并發(fā)清除過(guò)程中蛉拙,收集器線程都可以與用戶線程一起工作,所以總體上來(lái)說(shuō)彻亲,CMS收集器的內(nèi)存回收過(guò)程是與用戶線程一起并發(fā)地執(zhí)行孕锄。老年代收集器(新生代使用ParNew)
優(yōu)點(diǎn):并發(fā)收集、低停頓
缺點(diǎn):產(chǎn)生大量空間碎片苞尝、并發(fā)階段會(huì)降低吞吐量
采用“標(biāo)記-清除”算法實(shí)現(xiàn)畸肆,使用多線程的算法去掃描堆,對(duì)發(fā)現(xiàn)未使用的對(duì)象進(jìn)行回收宙址。
- (1)初始標(biāo)記
- (2)并發(fā)標(biāo)記
- (3)并發(fā)預(yù)處理
- (4)重新標(biāo)記
- (5)并發(fā)清除
- (6)并發(fā)重置
特點(diǎn):響應(yīng)時(shí)間優(yōu)先轴脐,減少垃圾收集停頓時(shí)間
適應(yīng)場(chǎng)景:大型服務(wù)器等。
通過(guò)JVM參數(shù) -XX:+UseConcMarkSweepGC設(shè)置
6抡砂、g1收集器
在G1中大咱,堆被劃分成 許多個(gè)連續(xù)的區(qū)域(region)。采用G1算法進(jìn)行回收注益,吸收了CMS收集器特點(diǎn)碴巾。
特點(diǎn):支持很大的堆,高吞吐量
- --支持多CPU和垃圾回收線程
- --在主線程暫停的情況下聊浅,使用并行收集
- --在主線程運(yùn)行的情況下餐抢,使用并發(fā)收集
實(shí)時(shí)目標(biāo):可配置在N毫秒內(nèi)最多只占用M毫秒的時(shí)間進(jìn)行垃圾回收
通過(guò)JVM參數(shù) -XX:+UseG1GC 使用G1垃圾回收器
注意: 并發(fā)是指一個(gè)處理器同時(shí)處理多個(gè)任務(wù)现使。
并行是指多個(gè)處理器或者是多核的處理器同時(shí)處理多個(gè)不同的任務(wù)。
并發(fā)是邏輯上的同時(shí)發(fā)生(simultaneous)旷痕,而并行是物理上的同時(shí)發(fā)生碳锈。
來(lái)個(gè)比喻:并發(fā)是一個(gè)人同時(shí)吃三個(gè)饅頭,而并行是三個(gè)人同時(shí)吃三個(gè)饅頭欺抗。
四售碳、Tomcat配置調(diào)優(yōu)測(cè)試
1、Jmeter壓力測(cè)試工具
JMeter是一款在國(guó)外非常流行和受歡迎的開(kāi)源性能測(cè)試工具绞呈,像LoadRunner 一樣贸人,它也提供了一個(gè)利用本地Proxy Server(代理服務(wù)器)來(lái)錄制生成測(cè)試腳本的功能,但是這個(gè)功能并不好用佃声。所以在本文中介紹一個(gè)更為常用的方法——使用Badboy錄制生成 JMeter 腳本艺智。
簡(jiǎn)單的介紹一下Badboy。Badboy是一款不錯(cuò)的Web自動(dòng)化測(cè)試工具圾亏,如果你將它用于非商業(yè)用途十拣,或者用于商業(yè)用途但是安裝Badboy 的機(jī)器數(shù)量不超過(guò)5臺(tái),你是不需要為它支付任何費(fèi)用的志鹃。也許是一種推廣策略夭问,Badboy提供了將Web測(cè)試腳本直接導(dǎo)出生成JMeter 腳本的功能,并且這個(gè)功能非常好用曹铃,也非常簡(jiǎn)單缰趋。你可以跟著下面的試驗(yàn)步驟來(lái)邁出你在開(kāi)源世界的第一步。
- 通過(guò)Badboy的官方網(wǎng)站下載Badboy的最新版本陕见;
- 安裝Badboy秘血。安裝過(guò)程同一般的Windows 應(yīng)用程序沒(méi)有什么區(qū)別,安裝完成后你可以在桌面和Windows開(kāi)始菜單中看到相應(yīng)的快捷方式——如果找不到淳玩,可以找一下Badboy安裝目錄下的Badboy.exe 文件直撤,直接雙擊啟動(dòng)Badboy;
- 啟動(dòng)Badboy蜕着,你可以看到下面的界面谋竖。
在地址欄(圖中紅色方框標(biāo)注的部分)中輸入你需要錄制的Web應(yīng)用的URL——這里我們以http://www.yahoo.com 為例,并點(diǎn)擊GO 按鈕開(kāi)始錄制承匣。 - 開(kāi)始錄制后蓖乘,你可以直接在Badboy內(nèi)嵌的瀏覽器(主界面的右側(cè))中對(duì)被測(cè)應(yīng)用進(jìn)行操作,所有的操作都會(huì)被記錄在主界面左側(cè)的編輯窗口中——在這個(gè)試驗(yàn)中韧骗,我們?cè)赮ahoo的搜索引擎中輸入 JMeter 進(jìn)行搜索嘉抒。不過(guò)你將看到,錄制下來(lái)的腳本并不是一行行的代碼袍暴,而是一個(gè)個(gè)Web對(duì)象——這就有點(diǎn)像LoadRunner的VuGen中的Tree View視圖些侍;
- 錄制完成后隶症,點(diǎn)擊工具欄中的“停止錄制”按鈕,完成腳本的錄制岗宣;
- 選擇“File -> Export to JMeter”菜單蚂会,填寫(xiě)文件名“l(fā)ogin_mantis.jmx”,將錄制好腳本導(dǎo)出為JMeter腳本格式耗式。也可以選擇“File -> Save”菜單保存為Badboy腳本胁住;
- 啟動(dòng)JMeter并打開(kāi)剛剛生成的測(cè)試腳本。
2刊咳、什么是吞吐量
QPS:Queries Per Second意思是“每秒查詢(xún)率”彪见,是一臺(tái)服務(wù)器每秒能夠相應(yīng)的查詢(xún)次數(shù),是對(duì)一個(gè)特定的查詢(xún)服務(wù)器在規(guī)定時(shí)間內(nèi)所處理流量多少的衡量標(biāo)準(zhǔn)娱挨。
3余指、測(cè)試
3.1、測(cè)試串行吞吐量
-XX:+PrintGCDetails -Xmx32M -Xms1M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseSerialGC
-XX:PermSize=32M
GC 回收次數(shù)25次 吞吐量4662
--> 堆的初始值和堆的最大一致
加大初始堆內(nèi)存大小-Xms1M 修改為32m
GC 回收次數(shù)7次 吞吐量5144
3.2让蕾、擴(kuò)大堆的內(nèi)存
-XX:+PrintGCDetails -Xmx512M -Xms32M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseSerialGC
-XX:PermSize=32M
GC 回收次數(shù)6次 吞吐量5141
結(jié)論:垃圾回收次數(shù)和設(shè)置最大堆內(nèi)存大小無(wú)關(guān)浪规,只和初始內(nèi)存有關(guān)系。
初始內(nèi)存會(huì)影響吞吐量探孝。
3.3、調(diào)整初始堆
-XX:+PrintGCDetails -Xmx512M –Xms512M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseSerialGC
-XX:PermSize=32M
GC回收次數(shù)0次 吞吐量6561次
結(jié)論:堆的初始值和最大堆內(nèi)存一致誉裆,并且初始堆越大就會(huì)高顿颅。
3.4、并行回收(UseParNewGC)
-XX:+PrintGCDetails -Xmx512M -Xms512M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseParNewGC
-XX:PermSize=32M
GC回收0次 吞吐量6800
3.5足丢、CMS收集器
-XX:+PrintGCDetails -Xmx512M -Xms512M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseConcMarkSweepGC
-XX:PermSize=32M
3.6粱腻、G1回收方式
-XX:+PrintGCDetails -Xmx512M -Xms512M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseG1GC
-XX:PermSize=32M
3、調(diào)優(yōu)總結(jié)
初始堆值和最大堆內(nèi)存內(nèi)存越大斩跌,吞吐量就越高绍些。
最好使用并行收集器,因?yàn)椴⑿惺占魉俣缺却型掏铝扛撸俣瓤臁?/p>
設(shè)置堆內(nèi)存新生代的比例和老年代的比例最好為1:2或者1:3耀鸦。
減少GC對(duì)老年代的回收柬批。
個(gè)人博客 蝸牛