GC的基礎(chǔ)知識
1.什么是垃圾
C語言申請內(nèi)存:malloc free
C++: new delete
c/C++ 手動回收內(nèi)存
Java: new ?
自動內(nèi)存回收,編程上簡單尝盼,系統(tǒng)不容易出錯植旧,手動釋放內(nèi)存,容易出兩種類型的問題:
- 忘記回收
- 多次回收
沒有任何引用指向的一個對象或者多個對象(循環(huán)引用)
2.如何定位垃圾
引用計數(shù)(ReferenceCount)
根可達(dá)算法(RootSearching)
3.常見的垃圾回收算法
標(biāo)記清除(mark sweep) - 位置不連續(xù) 產(chǎn)生碎片 效率偏低(兩遍掃描)
拷貝算法 (copying) - 沒有碎片慕淡,浪費空間
標(biāo)記壓縮(mark compact) - 沒有碎片背伴,效率偏低(兩遍掃描,指針需要調(diào)整)
4.JVM內(nèi)存分代模型(用于分代垃圾回收算法)
-
部分垃圾回收器使用的模型
除Epsilon ZGC Shenandoah之外的GC都是使用邏輯分代模型
G1是邏輯分代峰髓,物理不分代
除此之外不僅邏輯分代傻寂,而且物理分代
-
新生代 + 老年代 + 永久代(1.7)Perm Generation/ 元數(shù)據(jù)區(qū)(1.8) Metaspace
永久代 元數(shù)據(jù) - Class
永久代必須指定大小限制 ,元數(shù)據(jù)可以設(shè)置携兵,也可以不設(shè)置疾掰,無上限(受限于物理內(nèi)存)
字符串常量 1.7 - 永久代,1.8 - 堆
MethodArea邏輯概念 - 永久代徐紧、元數(shù)據(jù)
-
新生代 = Eden + 2個suvivor區(qū)
YGC回收之后静檬,大多數(shù)的對象會被回收,活著的進(jìn)入s0
再次YGC并级,活著的對象eden + s0 -> s1
再次YGC巴柿,eden + s1 -> s0
年齡足夠 -> 老年代 (15 CMS 6)
s區(qū)裝不下 -> 老年代
-
老年代
頑固分子
老年代滿了FGC Full GC
-
GC Tuning (Generation)
盡量減少FGC
MinorGC = YGC
MajorGC = FGC
對象分配過程圖
動態(tài)年齡:(不重要) http://www.reibang.com/p/989d3b06a49d
分配擔(dān)保:(不重要) YGC期間 survivor區(qū)空間不夠了 空間擔(dān)保直接進(jìn)入老年代 參考:https://cloud.tencent.com/developer/article/1082730
5.常見的垃圾回收器
垃圾回收器的發(fā)展路線,是隨著內(nèi)存越來越大的過程而演進(jìn) 從分代算法演化到不分代算法 Serial算法 幾十兆 Parallel算法 幾個G CMS 幾十個G - 承上啟下死遭,開始并發(fā)回收 - .- 三色標(biāo)記 -
JDK誕生 Serial追隨 提高效率广恢,誕生了PS,為了配合CMS呀潭,誕生了PN钉迷,CMS是1.4版本后期引入,CMS是里程碑式的GC钠署,它開啟了并發(fā)回收的過程糠聪,但是CMS毛病較多,因此目前任何一個JDK版本默認(rèn)是CMS 并發(fā)垃圾回收是因為無法忍受STW
Serial 年輕代 串行回收
PS 年輕代 并行回收
ParNew 年輕代 配合CMS的并行回收
SerialOld
ParallelOld
ConcurrentMarkSweep 老年代 并發(fā)的谐鼎, 垃圾回收和應(yīng)用程序同時運(yùn)行舰蟆,降低STW的時間(200ms) CMS問題比較多,所以現(xiàn)在沒有一個版本默認(rèn)是CMS,只能手工指定 CMS既然是MarkSweep身害,就一定會有碎片化的問題味悄,碎片到達(dá)一定程度,CMS的老年代分配對象分配不下的時候塌鸯,使用SerialOld 進(jìn)行老年代回收 想象一下: PS + PO -> 加內(nèi)存 換垃圾回收器 -> PN + CMS + SerialOld(幾個小時 - 幾天的STW) 幾十個G的內(nèi)存侍瑟,單線程回收 -> G1 + FGC 幾十個G -> 上T內(nèi)存的服務(wù)器 ZGC 算法:三色標(biāo)記 + Incremental Update
G1(200ms - 10ms) 算法:三色標(biāo)記 + SATB
ZGC (10ms - 1ms) PK C++ 算法:ColoredPointers + LoadBarrier
Shenandoah 算法:ColoredPointers + WriteBarrier
Eplison
PS 和 PN區(qū)別的延伸閱讀: ?https://docs.oracle.com/en/java/javase/13/gctuning/ergonomics.html#GUID-3D0BB91E-9BFF-4EBB-B523-14493A860E73
垃圾收集器跟內(nèi)存大小的關(guān)系
Serial 幾十兆
PS 上百兆 - 幾個G
CMS - 20G
G1 - 上百G
ZGC - 4T - 16T(JDK13)
1.8默認(rèn)的垃圾回收:PS + ParallelOld
常見垃圾回收器組合參數(shù)設(shè)定:(1.8)
-
-XX:+UseSerialGC = Serial New (DefNew) + Serial Old
- 小型程序。默認(rèn)情況下不會是這種選項丙猬,HotSpot會根據(jù)計算及配置和JDK版本自動選擇收集器
-
-XX:+UseParNewGC = ParNew + SerialOld
這個組合已經(jīng)很少用(在某些版本中已經(jīng)廢棄)
-XX:+UseConc(urrent)MarkSweepGC = ParNew + CMS + Serial Old
-XX:+UseParallelGC = Parallel Scavenge + Parallel Old (1.8默認(rèn)) 【PS + SerialOld】
-XX:+UseParallelOldGC = Parallel Scavenge + Parallel Old
-XX:+UseG1GC = G1
-
Linux中沒找到默認(rèn)GC的查看方法涨颜,而windows中會打印UseParallelGC
java +XX:+PrintCommandLineFlags -version
通過GC的日志來分辨
-
Linux下1.8版本默認(rèn)的垃圾回收器到底是什么?
1.8.0_181 默認(rèn)(看不出來)Copy MarkCompact
1.8.0_222 默認(rèn) PS + PO
JVM調(diào)優(yōu)第一步茧球,了解JVM常用命令行參數(shù)
JVM的命令行參數(shù)參考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
-
HotSpot參數(shù)分類
標(biāo)準(zhǔn): - 開頭庭瑰,所有的HotSpot都支持
非標(biāo)準(zhǔn):-X 開頭,特定版本HotSpot支持特定命令
不穩(wěn)定:-XX 開頭抢埋,下個版本可能取消
java -version
java -X
java -XX:+PrintFlagsWithComments //只有debug版本能用
試驗用程序:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n180" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); --select-text-bg-color: #36284e; --select-text-font-color: #fff; font-size: 0.9rem; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 3em; margin-left: 2em; padding-left: 1ch; padding-right: 1ch; width: inherit;">import java.util.List;
import java.util.LinkedList;public class HelloGC {
public static void main(String[] args) {
System.out.println("HelloGC!");
List list = new LinkedList();
for(;;) {
byte[] b = new byte[1024*1024];
list.add(b);
}
}
}</pre>區(qū)分概念:內(nèi)存泄漏memory leak弹灭,內(nèi)存溢出out of memory
java -XX:+PrintCommandLineFlags HelloGC
java -Xmn10M -Xms40M -Xmx60M -XX:+PrintCommandLineFlags -XX:+PrintGC HelloGC PrintGCDetails PrintGCTimeStamps PrintGCCauses
java -XX:+UseConcMarkSweepGC -XX:+PrintCommandLineFlags HelloGC
java -XX:+PrintFlagsInitial 默認(rèn)參數(shù)值
java -XX:+PrintFlagsFinal 最終參數(shù)值
java -XX:+PrintFlagsFinal | grep xxx 找到對應(yīng)的參數(shù)
java -XX:+PrintFlagsFinal -version |grep GC
java -XX:+PrintFlagsFinal -version | wc -l 共728個參數(shù)
PS GC日志詳解
每種垃圾回收器的日志格式是不同的!
PS日志格式
heap dump部分:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n206" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); --select-text-bg-color: #36284e; --select-text-font-color: #fff; font-size: 0.9rem; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 3em; margin-left: 2em; padding-left: 1ch; padding-right: 1ch; width: inherit; color: rgb(31, 9, 9); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">eden space 5632K, 94% used [0x00000000ff980000,0x00000000ffeb3e28,0x00000000fff00000)
后面的內(nèi)存地址指的是羹令,起始地址鲤屡,使用空間結(jié)束地址,整體空間結(jié)束地址</pre>
total = eden + 1個survivor
調(diào)優(yōu)前的基礎(chǔ)概念:
吞吐量:用戶代碼時間 /(用戶代碼執(zhí)行時間 + 垃圾回收時間)
響應(yīng)時間:STW越短福侈,響應(yīng)時間越好
所謂調(diào)優(yōu)酒来,首先確定,追求啥肪凛?吞吐量優(yōu)先堰汉,還是響應(yīng)時間優(yōu)先?還是在滿足一定的響應(yīng)時間的情況下伟墙,要求達(dá)到多大的吞吐量...
問題:
科學(xué)計算翘鸭,吞吐量。數(shù)據(jù)挖掘戳葵,thrput就乓。吞吐量優(yōu)先的一般:(PS + PO)
響應(yīng)時間:網(wǎng)站 GUI API (1.8 G1)
什么是調(diào)優(yōu)?
根據(jù)需求進(jìn)行JVM規(guī)劃和預(yù)調(diào)優(yōu)
優(yōu)化運(yùn)行JVM運(yùn)行環(huán)境(慢拱烁,卡頓)
解決JVM運(yùn)行過程中出現(xiàn)的各種問題(OOM)
調(diào)優(yōu)生蚁,從規(guī)劃開始
調(diào)優(yōu),從業(yè)務(wù)場景開始戏自,沒有業(yè)務(wù)場景的調(diào)優(yōu)都是耍流氓
無監(jiān)控(壓力測試邦投,能看到結(jié)果),不調(diào)優(yōu)
-
步驟:
-
熟悉業(yè)務(wù)場景(沒有最好的垃圾回收器擅笔,只有最合適的垃圾回收器)
響應(yīng)時間志衣、停頓時間 [CMS G1 ZGC] (需要給用戶作響應(yīng))
吞吐量 = 用戶時間 /( 用戶時間 + GC時間) [PS]
選擇回收器組合
計算內(nèi)存需求(經(jīng)驗值 1.5G 16G)
選定CPU(越高越好)
設(shè)定年代大小屯援、升級年齡
-
設(shè)定日志參數(shù)
-Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause
或者每天產(chǎn)生一個日志文件
觀察日志情況
-
-
案例1:垂直電商,最高每日百萬訂單念脯,處理訂單系統(tǒng)需要什么樣的服務(wù)器配置狞洋?
這個問題比較業(yè)余,因為很多不同的服務(wù)器配置都能支撐(1.5G 16G)
1小時360000集中時間段和二, 100個訂單/秒徘铝,(找一小時內(nèi)的高峰期耳胎,1000訂單/秒)
經(jīng)驗值惯吕,
非要計算:一個訂單產(chǎn)生需要多少內(nèi)存?512K * 1000 500M內(nèi)存
專業(yè)一點兒問法:要求響應(yīng)時間100ms
壓測怕午!
-
案例2:12306遭遇春節(jié)大規(guī)模搶票應(yīng)該如何支撐废登?
12306應(yīng)該是中國并發(fā)量最大的秒殺網(wǎng)站:
號稱并發(fā)量100W最高
CDN -> LVS -> NGINX -> 業(yè)務(wù)系統(tǒng) -> 每臺機(jī)器1W并發(fā)(10K問題) 100臺機(jī)器
普通電商訂單 -> 下單 ->訂單系統(tǒng)(IO)減庫存 ->等待用戶付款
12306的一種可能的模型: 下單 -> 減庫存 和 訂單(redis kafka) 同時異步進(jìn)行 ->等付款
減庫存最后還會把壓力壓到一臺服務(wù)器
可以做分布式本地庫存 + 單獨服務(wù)器做庫存均衡
大流量的處理方法:分而治之
-
怎么得到一個事務(wù)會消耗多少內(nèi)存?
- 弄臺機(jī)器郁惜,看能承受多少TPS堡距?是不是達(dá)到目標(biāo)?擴(kuò)容或調(diào)優(yōu)兆蕉,讓它達(dá)到
- 用壓測來確定
優(yōu)化環(huán)境
-
有一個50萬PV的資料類網(wǎng)站(從磁盤提取文檔到內(nèi)存)原服務(wù)器32位羽戒,1.5G 的堆,用戶反饋網(wǎng)站比較緩慢虎韵,因此公司決定升級易稠,新的服務(wù)器為64位,16G 的堆內(nèi)存包蓝,結(jié)果用戶反饋卡頓十分嚴(yán)重驶社,反而比以前效率更低了
為什么原網(wǎng)站慢? 很多用戶瀏覽數(shù)據(jù),很多數(shù)據(jù)load到內(nèi)存测萎,內(nèi)存不足亡电,頻繁GC,STW長硅瞧,響應(yīng)時間變慢
為什么會更卡頓份乒? 內(nèi)存越大,F(xiàn)GC時間越長
咋辦腕唧? PS -> PN + CMS 或者 G1
-
系統(tǒng)CPU經(jīng)常100%或辖,如何調(diào)優(yōu)?(面試高頻) CPU100%那么一定有線程在占用系統(tǒng)資源四苇,
找出哪個進(jìn)程cpu高(top)
該進(jìn)程中的哪個線程cpu高(top -Hp)
導(dǎo)出該線程的堆棧 (jstack)
查找哪個方法(棧幀)消耗時間 (jstack)
工作線程占比高 | 垃圾回收線程占比高
-
系統(tǒng)內(nèi)存飆高孝凌,如何查找問題?(面試高頻)
導(dǎo)出堆內(nèi)存 (jmap)
分析 (jhat jvisualvm mat jprofiler ... )
-
如何監(jiān)控JVM
- jstat jvisualvm jprofiler arthas top...
解決JVM運(yùn)行中的問題
一個案例理解常用工具
-
測試代碼:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n329" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); --select-text-bg-color: #36284e; --select-text-font-color: #fff; font-size: 0.9rem; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 3em; margin-left: 2em; padding-left: 1ch; padding-right: 1ch; width: inherit;">package com.mashibing.jvm.gc;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;/**
- 從數(shù)據(jù)庫中讀取信用數(shù)據(jù)月腋,套用模型蟀架,并把結(jié)果進(jìn)行記錄和傳輸
*/
public class T15_FullGC_Problem01 {
private static class CardInfo {
BigDecimal price = new BigDecimal(0.0);
String name = "張三";
int age = 5;
Date birthdate = new Date();public void m() {}
}private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50,
new ThreadPoolExecutor.DiscardOldestPolicy());public static void main(String[] args) throws Exception {
executor.setMaximumPoolSize(50);for (;;){
modelFit();
Thread.sleep(100);
}
}private static void modelFit(){
List<CardInfo> taskList = getAllCardInfo();
taskList.forEach(info -> {
// do something
executor.scheduleWithFixedDelay(() -> {
//do sth with info
info.m();}, 2, 3, TimeUnit.SECONDS);
});
}private static List<CardInfo> getAllCardInfo(){
List<CardInfo> taskList = new ArrayList<>();for (int i = 0; i < 100; i++) {
CardInfo ci = new CardInfo();
taskList.add(ci);
}return taskList;
}
}
</pre> - 從數(shù)據(jù)庫中讀取信用數(shù)據(jù)月腋,套用模型蟀架,并把結(jié)果進(jìn)行記錄和傳輸
java -Xms200M -Xmx200M -XX:+PrintGC com.mashibing.jvm.gc.T15_FullGC_Problem01
一般是運(yùn)維團(tuán)隊首先受到報警信息(CPU Memory)
top命令觀察到問題:內(nèi)存不斷增長 CPU占用率居高不下
top -Hp 觀察進(jìn)程中的線程瓣赂,哪個線程CPU和內(nèi)存占比高
jps定位具體java進(jìn)程 jstack 定位線程狀況,重點關(guān)注:WAITING BLOCKED eg. waiting on <0x0000000088ca3310> (a java.lang.Object) 假如有一個進(jìn)程中100個線程片拍,很多線程都在waiting on <xx> 煌集,一定要找到是哪個線程持有這把鎖 怎么找?搜索jstack dump的信息捌省,找<xx> 苫纤,看哪個線程持有這把鎖RUNNABLE 作業(yè):1:寫一個死鎖程序,用jstack觀察 2 :寫一個程序纲缓,一個線程持有鎖不釋放卷拘,其他線程等待
為什么阿里規(guī)范里規(guī)定,線程的名稱(尤其是線程池)都要寫有意義的名稱 怎么樣自定義線程池里的線程名稱祝高?(自定義ThreadFactory)
jinfo pid
jstat -gc 動態(tài)觀察gc情況 / 閱讀GC日志發(fā)現(xiàn)頻繁GC / arthas觀察 / jconsole/jvisualVM/ Jprofiler(最好用) jstat -gc 4655 500 : 每個500個毫秒打印GC的情況 如果面試官問你是怎么定位OOM問題的栗弟?如果你回答用圖形界面(錯誤) 1:已經(jīng)上線的系統(tǒng)不用圖形界面用什么?(cmdline arthas) 2:圖形界面到底用在什么地方工闺?測試乍赫!測試的時候進(jìn)行監(jiān)控!(壓測觀察)
jmap - histo 4655 | head -20陆蟆,查找有多少對象產(chǎn)生
jmap -dump:format=b,file=xxx pid :
線上系統(tǒng)雷厂,內(nèi)存特別大,jmap執(zhí)行期間會對進(jìn)程產(chǎn)生很大影響叠殷,甚至卡頓(電商不適合) 1:設(shè)定了參數(shù)HeapDump改鲫,OOM的時候會自動產(chǎn)生堆轉(zhuǎn)儲文件(不是很專業(yè),因為多有監(jiān)控溪猿,內(nèi)存增長就會報警) 2:很多服務(wù)器備份(高可用)钩杰,停掉這臺服務(wù)器對其他服務(wù)器不影響 3:在線定位(一般小點兒公司用不到)
4:在測試環(huán)境中壓測(產(chǎn)生類似內(nèi)存增長問題,在堆還不是很大的時候進(jìn)行轉(zhuǎn)儲)
java -Xms20M -Xmx20M -XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError com.mashibing.jvm.gc.T15_FullGC_Problem01
使用MAT / jhat /jvisualvm 進(jìn)行dump文件分析 https://www.cnblogs.com/baihuitestsoftware/articles/6406271.html jhat -J-mx512M xxx.dump http://192.168.17.11:7000 拉到最后:找到對應(yīng)鏈接 可以使用OQL查找特定問題對象
找到代碼的問題
jconsole遠(yuǎn)程連接
-
程序啟動加入?yún)?shù):
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="shell" cid="n363" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); --select-text-bg-color: #36284e; --select-text-font-color: #fff; font-size: 0.9rem; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 0px; margin-left: 2em; padding-left: 1ch; padding-right: 1ch; margin-top: 0px; width: inherit;">java -Djava.rmi.server.hostname=192.168.17.11 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=11111 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false XXX</pre>
-
如果遭遇 Local host name unknown:XXX的錯誤诊县,修改/etc/hosts文件讲弄,把XXX加入進(jìn)去
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n367" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); --select-text-bg-color: #36284e; --select-text-font-color: #fff; font-size: 0.9rem; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 0px; margin-left: 2em; padding-left: 1ch; padding-right: 1ch; margin-top: 0px; width: inherit;">192.168.17.11 basic localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6</pre> -
關(guān)閉linux防火墻(實戰(zhàn)中應(yīng)該打開對應(yīng)端口)
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="shell" cid="n371" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); --select-text-bg-color: #36284e; --select-text-font-color: #fff; font-size: 0.9rem; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 0px; margin-left: 2em; padding-left: 1ch; padding-right: 1ch; margin-top: 0px; width: inherit;">service iptables stop
chkconfig iptables off #永久關(guān)閉</pre> windows上打開 jconsole遠(yuǎn)程連接 192.168.17.11:11111
jvisualvm遠(yuǎn)程連接
https://www.cnblogs.com/liugh/p/7620336.html (簡單做法)
jprofiler (收費)
arthas在線排查工具
為什么需要在線排查? 在生產(chǎn)上我們經(jīng)常會碰到一些不好排查的問題依痊,例如線程安全問題避除,用最簡單的threaddump或者h(yuǎn)eapdump不好查到問題原因。為了排查這些問題胸嘁,有時我們會臨時加一些日志瓶摆,比如在一些關(guān)鍵的函數(shù)里打印出入?yún)ⅲ缓笾匦麓虬l(fā)布性宏,如果打了日志還是沒找到問題群井,繼續(xù)加日志,重新打包發(fā)布毫胜。對于上線流程復(fù)雜而且審核比較嚴(yán)的公司书斜,從改代碼到上線需要層層的流轉(zhuǎn)诬辈,會大大影響問題排查的進(jìn)度。
jvm觀察jvm信息
thread定位線程問題
dashboard 觀察系統(tǒng)情況
heapdump + jhat分析
jad反編譯 動態(tài)代理生成類的問題定位 第三方的類(觀察代碼) 版本問題(確定自己最新提交的版本是不是被使用)
redefine 熱替換 目前有些限制條件:只能改方法實現(xiàn)(方法已經(jīng)運(yùn)行完成)荐吉,不能改方法名焙糟, 不能改屬性 m() -> mm()
sc - search class
watch - watch method
沒有包含的功能:jmap
GC算法的基礎(chǔ)概念
- Card Table 由于做YGC時,需要掃描整個OLD區(qū)样屠,效率非常低穿撮,所以JVM設(shè)計了CardTable, 如果一個OLD區(qū)CardTable中有對象指向Y區(qū)痪欲,就將它設(shè)為Dirty悦穿,下次掃描時,只需要掃描Dirty Card 在結(jié)構(gòu)上勤揩,Card Table用BitMap來實現(xiàn)
CMS
CMS的問題
-
Memory Fragmentation
-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction 默認(rèn)為0 指的是經(jīng)過多少次FGC才進(jìn)行壓縮
-
Floating Garbage
Concurrent Mode Failure 產(chǎn)生:if the concurrent collector is unable to finish reclaiming the unreachable objects before the tenured generation fills up, or if an allocation cannot be satisfiedwith the available free space blocks in the tenured generation, then theapplication is paused and the collection is completed with all the applicationthreads stopped
解決方案:降低觸發(fā)CMS的閾值
PromotionFailed
解決方案類似咧党,保持老年代有足夠的空間
–XX:CMSInitiatingOccupancyFraction 92% 可以降低這個值秘蛔,讓CMS保持老年代足夠的空間
CMS日志分析
執(zhí)行命令:java -Xms20M -Xmx20M -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC com.mashibing.jvm.gc.T15_FullGC_Problem01
[GC (Allocation Failure) [ParNew: 6144K->640K(6144K), 0.0265885 secs] 6585K->2770K(19840K), 0.0268035 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
ParNew:年輕代收集器
6144->640:收集前后的對比
(6144):整個年輕代容量
6585 -> 2770:整個堆的情況
(19840):整個堆大小
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n428" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); --select-text-bg-color: #36284e; --select-text-font-color: #fff; font-size: 0.9rem; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 3em; margin-left: 2em; padding-left: 1ch; padding-right: 1ch; width: inherit; color: rgb(31, 9, 9); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">[GC (CMS Initial Mark) [1 CMS-initial-mark: 8511K(13696K)] 9866K(19840K), 0.0040321 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
//8511 (13696) : 老年代使用(最大)
//9866 (19840) : 整個堆使用(最大)
[CMS-concurrent-mark-start]
[CMS-concurrent-mark: 0.018/0.018 secs] [Times: user=0.01 sys=0.00, real=0.02 secs]
//這里的時間意義不大陨亡,因為是并發(fā)執(zhí)行
[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//標(biāo)記Card為Dirty,也稱為Card Marking
[GC (CMS Final Remark) [YG occupancy: 1597 K (6144 K)][Rescan (parallel) , 0.0008396 secs][weak refs processing, 0.0000138 secs][class unloading, 0.0005404 secs][scrub symbol table, 0.0006169 secs][scrub string table, 0.0004903 secs][1 CMS-remark: 8511K(13696K)] 10108K(19840K), 0.0039567 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//STW階段深员,YG occupancy:年輕代占用及容量
//[Rescan (parallel):STW下的存活對象標(biāo)記
//weak refs processing: 弱引用處理
//class unloading: 卸載用不到的class
//scrub symbol(string) table:
//cleaning up symbol and string tables which hold class-level metadata and
//internalized string respectively
//CMS-remark: 8511K(13696K): 階段過后的老年代占用及容量
//10108K(19840K): 階段過后的堆占用及容量
[CMS-concurrent-sweep-start]
[CMS-concurrent-sweep: 0.005/0.005 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
//標(biāo)記已經(jīng)完成负蠕,進(jìn)行并發(fā)清理
[CMS-concurrent-reset-start]
[CMS-concurrent-reset: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//重置內(nèi)部結(jié)構(gòu),為下次GC做準(zhǔn)備</pre>
G1
G1日志詳解
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n435" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); --select-text-bg-color: #36284e; --select-text-font-color: #fff; font-size: 0.9rem; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 3em; margin-left: 2em; padding-left: 1ch; padding-right: 1ch; width: inherit; color: rgb(31, 9, 9); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">[GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0015790 secs]
//young -> 年輕代 Evacuation-> 復(fù)制存活對象
//initial-mark 混合回收的階段倦畅,這里是YGC混合老年代回收
[Parallel Time: 1.5 ms, GC Workers: 1] //一個GC線程
[GC Worker Start (ms): 92635.7]
[Ext Root Scanning (ms): 1.1]
[Update RS (ms): 0.0]
[Processed Buffers: 1]
[Scan RS (ms): 0.0]
[Code Root Scanning (ms): 0.0]
[Object Copy (ms): 0.1]
[Termination (ms): 0.0]
[Termination Attempts: 1]
[GC Worker Other (ms): 0.0]
[GC Worker Total (ms): 1.2]
[GC Worker End (ms): 92636.9]
[Code Root Fixup: 0.0 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.0 ms]
[Other: 0.1 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 0.0 ms]
[Ref Enq: 0.0 ms]
[Redirty Cards: 0.0 ms]
[Humongous Register: 0.0 ms]
[Humongous Reclaim: 0.0 ms]
[Free CSet: 0.0 ms]
[Eden: 0.0B(1024.0K)->0.0B(1024.0K) Survivors: 0.0B->0.0B Heap: 18.8M(20.0M)->18.8M(20.0M)]
[Times: user=0.00 sys=0.00, real=0.00 secs]
//以下是混合回收其他階段
[GC concurrent-root-region-scan-start]
[GC concurrent-root-region-scan-end, 0.0000078 secs]
[GC concurrent-mark-start]
//無法evacuation遮糖,進(jìn)行FGC
[Full GC (Allocation Failure) 18M->18M(20M), 0.0719656 secs]
[Eden: 0.0B(1024.0K)->0.0B(1024.0K) Survivors: 0.0B->0.0B Heap: 18.8M(20.0M)->18.8M(20.0M)], [Metaspace: 38
76K->3876K(1056768K)] [Times: user=0.07 sys=0.00, real=0.07 secs]
</pre>
案例匯總
OOM產(chǎn)生的原因多種多樣,有些程序未必產(chǎn)生OOM叠赐,不斷FGC(CPU飆高欲账,但內(nèi)存回收特別少) (上面案例)
硬件升級系統(tǒng)反而卡頓的問題(見上)
線程池不當(dāng)運(yùn)用產(chǎn)生OOM問題(見上) 不斷的往List里加對象(實在太LOW)
smile jira問題 實際系統(tǒng)不斷重啟 解決問題 加內(nèi)存 + 更換垃圾回收器 G1 真正問題在哪兒?不知道
tomcat http-header-size過大問題(Hector)
-
lambda表達(dá)式導(dǎo)致方法區(qū)溢出問題(MethodArea / Perm Metaspace) LambdaGC.java -XX:MaxMetaspaceSize=9M -XX:+PrintGCDetails
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n450" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); --select-text-bg-color: #36284e; --select-text-font-color: #fff; font-size: 0.9rem; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 3em; margin-left: 2em; padding-left: 1ch; padding-right: 1ch; width: inherit;">"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" -XX:MaxMetaspaceSize=9M -XX:+PrintGCDetails "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.1\lib\idea_rt.jar=49316:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;C:\work\ijprojects\JVM\out\production\JVM;C:\work\ijprojects\ObjectSize\out\artifacts\ObjectSize_jar\ObjectSize.jar" com.mashibing.jvm.gc.LambdaGC
[GC (Metadata GC Threshold) [PSYoungGen: 11341K->1880K(38400K)] 11341K->1888K(125952K), 0.0022190 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Metadata GC Threshold) [PSYoungGen: 1880K->0K(38400K)] [ParOldGen: 8K->1777K(35328K)] 1888K->1777K(73728K), [Metaspace: 8164K->8164K(1056768K)], 0.0100681 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
[GC (Last ditch collection) [PSYoungGen: 0K->0K(38400K)] 1777K->1777K(73728K), 0.0005698 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Last ditch collection) [PSYoungGen: 0K->0K(38400K)] [ParOldGen: 1777K->1629K(67584K)] 1777K->1629K(105984K), [Metaspace: 8164K->8156K(1056768K)], 0.0124299 secs] [Times: user=0.06 sys=0.00, real=0.01 secs]
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:388)
at sun.instrument.InstrumentationImpl.loadClassAndCallAgentmain(InstrumentationImpl.java:411)
Caused by: java.lang.OutOfMemoryError: Compressed class space
at sun.misc.Unsafe.defineClass(Native Method)
at sun.reflect.ClassDefiner.defineClass(ClassDefiner.java:63)
at sun.reflect.MethodAccessorGenerator1.run(MethodAccessorGenerator.java:394)
at java.security.AccessController.doPrivileged(Native Method)
at sun.reflect.MethodAccessorGenerator.generate(MethodAccessorGenerator.java:393)
at sun.reflect.MethodAccessorGenerator.generateSerializationConstructor(MethodAccessorGenerator.java:112)
at sun.reflect.ReflectionFactory.generateConstructor(ReflectionFactory.java:398)
at sun.reflect.ReflectionFactory.newConstructorForSerialization(ReflectionFactory.java:360)
at java.io.ObjectStreamClass.getSerializableConstructor(ObjectStreamClass.java:1574)
at java.io.ObjectStreamClass.access3.run(ObjectStreamClass.java:519)
at java.io.ObjectStreamClass$3.run(ObjectStreamClass.java:494)
at java.security.AccessController.doPrivileged(Native Method)
at java.io.ObjectStreamClass.<init>(ObjectStreamClass.java:494)
at java.io.ObjectStreamClass.lookup(ObjectStreamClass.java:391)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1134)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at javax.management.remote.rmi.RMIConnectorServer.encodeJRMPStub(RMIConnectorServer.java:727)
at javax.management.remote.rmi.RMIConnectorServer.encodeStub(RMIConnectorServer.java:719)
at javax.management.remote.rmi.RMIConnectorServer.encodeStubInAddress(RMIConnectorServer.java:690)
at javax.management.remote.rmi.RMIConnectorServer.start(RMIConnectorServer.java:439)
at sun.management.jmxremote.ConnectorBootstrap.startLocalConnectorServer(ConnectorBootstrap.java:550)
at sun.management.Agent.startLocalManagementAgent(Agent.java:137)
</pre> 直接內(nèi)存溢出問題(少見) 《深入理解Java虛擬機(jī)》P59芭概,使用Unsafe分配直接內(nèi)存赛不,或者使用NIO的問題
棧溢出問題 -Xss設(shè)定太小
-
比較一下這兩段程序的異同,分析哪一個是更優(yōu)的寫法:
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java " cid="n457" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); --select-text-bg-color: #36284e; --select-text-font-color: #fff; font-size: 0.9rem; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 3em; margin-left: 2em; padding-left: 1ch; padding-right: 1ch; width: inherit;">Object o = null;
for(int i=0; i<100; i++) {
o = new Object();
//業(yè)務(wù)處理
}</pre><pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n458" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); --select-text-bg-color: #36284e; --select-text-font-color: #fff; font-size: 0.9rem; line-height: 1.71429em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(218, 218, 218); position: relative !important; margin-bottom: 3em; margin-left: 2em; padding-left: 1ch; padding-right: 1ch; width: inherit;">for(int i=0; i<100; i++) {
Object o = new Object();
}</pre> 重寫finalize引發(fā)頻繁GC 小米云罢洲,HBase同步系統(tǒng)踢故,系統(tǒng)通過nginx訪問超時報警,最后排查惹苗,C++程序員重寫finalize引發(fā)頻繁GC問題 為什么C++程序員會重寫finalize殿较?(new delete) finalize耗時比較長(200ms)
如果有一個系統(tǒng),內(nèi)存一直消耗不超過10%桩蓉,但是觀察GC日志淋纲,發(fā)現(xiàn)FGC總是頻繁產(chǎn)生,會是什么引起的院究? System.gc() (這個比較Low)
Distuptor有個可以設(shè)置鏈的長度洽瞬,如果過大玷或,然后對象大,消費完不主動釋放片任,會溢出 (來自 死物風(fēng)情)
用jvm都會溢出偏友,mycat用崩過,1.6.5某個臨時版本解析sql子查詢算法有問題对供,9個exists的聯(lián)合sql就導(dǎo)致生成幾百萬的對象(來自 死物風(fēng)情)
new 大量線程位他,會產(chǎn)生 native thread OOM,(low)應(yīng)該用線程池产场, 解決方案:減少堆空間(太TMlow了),預(yù)留更多內(nèi)存產(chǎn)生native thread JVM內(nèi)存占物理內(nèi)存比例 50% - 80%
近期學(xué)生案例SQLLite的類庫鹅髓,批處理的時候會把所有的結(jié)果加載內(nèi)存,有的人一下子更新幾十萬條數(shù)據(jù)京景,結(jié)果就產(chǎn)生了內(nèi)存溢出窿冯,定位上用的是排除法,去掉這個模塊就沒問題确徙,加上該模塊就會出問題
java在線解壓以及壓縮文件造成的內(nèi)存溢出
java使用opencv造成的卡頓與緩慢
最容易引起崩潰的報表系統(tǒng)
分庫分表所引起的系統(tǒng)崩潰
GC常用參數(shù)
-Xmn -Xms -Xmx -Xss 年輕代 最小堆 最大堆 椥汛空間
-XX:+UseTLAB 使用TLAB,默認(rèn)打開
-XX:+PrintTLAB 打印TLAB的使用情況
-XX:TLABSize 設(shè)置TLAB大小
-XX:+DisableExplictGC System.gc()不管用 鄙皇,F(xiàn)GC
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintHeapAtGC
-XX:+PrintGCTimeStamps
-XX:+PrintGCApplicationConcurrentTime (低) 打印應(yīng)用程序時間
-XX:+PrintGCApplicationStoppedTime (低) 打印暫停時長
-XX:+PrintReferenceGC (重要性低) 記錄回收了多少種不同引用類型的引用
-verbose:class 類加載詳細(xì)過程
-XX:+PrintVMOptions
-XX:+PrintFlagsFinal -XX:+PrintFlagsInitial 必須會用
-Xloggc:opt/log/gc.log
-XX:MaxTenuringThreshold 升代年齡芜赌,最大值15
鎖自旋次數(shù) -XX:PreBlockSpin 熱點代碼檢測參數(shù)-XX:CompileThreshold 逃逸分析 標(biāo)量替換 ... 這些不建議設(shè)置
Parallel常用參數(shù)
-XX:SurvivorRatio
-XX:PreTenureSizeThreshold 大對象到底多大
-XX:MaxTenuringThreshold
-XX:+ParallelGCThreads 并行收集器的線程數(shù),同樣適用于CMS伴逸,一般設(shè)為和CPU核數(shù)相同
-XX:+UseAdaptiveSizePolicy 自動選擇各區(qū)大小比例
CMS常用參數(shù)
-XX:+UseConcMarkSweepGC
-XX:ParallelCMSThreads CMS線程數(shù)量
-XX:CMSInitiatingOccupancyFraction 使用多少比例的老年代后開始CMS收集缠沈,默認(rèn)是68%(近似值),如果頻繁發(fā)生SerialOld卡頓错蝴,應(yīng)該調(diào)小洲愤,(頻繁CMS回收)
-XX:+UseCMSCompactAtFullCollection 在FGC時進(jìn)行壓縮
-XX:CMSFullGCsBeforeCompaction 多少次FGC之后進(jìn)行壓縮
-XX:+CMSClassUnloadingEnabled
-XX:CMSInitiatingPermOccupancyFraction 達(dá)到什么比例時進(jìn)行Perm回收
GCTimeRatio 設(shè)置GC時間占用程序運(yùn)行時間的百分比
-XX:MaxGCPauseMillis 停頓時間,是一個建議時間顷锰,GC會嘗試用各種手段達(dá)到這個時間柬赐,比如減小年輕代
G1常用參數(shù)
-XX:+UseG1GC
-XX:MaxGCPauseMillis 建議值,G1會嘗試調(diào)整Young區(qū)的塊數(shù)來達(dá)到這個值
-XX:GCPauseIntervalMillis 馍惹?GC的間隔時間
-XX:+G1HeapRegionSize 分區(qū)大小躺率,建議逐漸增大該值,1 2 4 8 16 32万矾。 隨著size增加悼吱,垃圾的存活時間更長,GC間隔更長良狈,但每次GC的時間也會更長 ZGC做了改進(jìn)(動態(tài)區(qū)塊大泻筇怼)
G1NewSizePercent 新生代最小比例,默認(rèn)為5%
G1MaxNewSizePercent 新生代最大比例薪丁,默認(rèn)為60%
GCTimeRatio GC時間建議比例遇西,G1會根據(jù)這個值調(diào)整堆空間
ConcGCThreads 線程數(shù)量
InitiatingHeapOccupancyPercent 啟動G1的堆空間占用比例
作業(yè)
-XX:MaxTenuringThreshold控制的是什么馅精? A: 對象升入老年代的年齡 B: 老年代觸發(fā)FGC時的內(nèi)存垃圾比例
生產(chǎn)環(huán)境中,傾向于將最大堆內(nèi)存和最小堆內(nèi)存設(shè)置為:(為什么粱檀?) A: 相同 B:不同
JDK1.8默認(rèn)的垃圾回收器是: A: ParNew + CMS B: G1 C: PS + ParallelOld D: 以上都不是
什么是響應(yīng)時間優(yōu)先洲敢?
什么是吞吐量優(yōu)先?
ParNew和PS的區(qū)別是什么茄蚯?
ParNew和ParallelOld的區(qū)別是什么压彭?(年代不同,算法不同)
長時間計算的場景應(yīng)該選擇:A:停頓時間 B: 吞吐量
大規(guī)模電商網(wǎng)站應(yīng)該選擇:A:停頓時間 B: 吞吐量
HotSpot的垃圾收集器最常用有哪些渗常?
常見的HotSpot垃圾收集器組合有哪些壮不?
JDK1.7 1.8 1.9的默認(rèn)垃圾回收器是什么?如何查看皱碘?
所謂調(diào)優(yōu)询一,到底是在調(diào)什么?
如果采用PS + ParrallelOld組合癌椿,怎么做才能讓系統(tǒng)基本不產(chǎn)生FGC
如果采用ParNew + CMS組合健蕊,怎樣做才能夠讓系統(tǒng)基本不產(chǎn)生FGC
1.加大JVM內(nèi)存
2.加大Young的比例
3.提高Y-O的年齡
4.提高S區(qū)比例
5.避免代碼內(nèi)存泄漏
G1是否分代?G1垃圾回收器會產(chǎn)生FGC嗎如失?
如果G1產(chǎn)生FGC绊诲,你應(yīng)該做什么?
擴(kuò)內(nèi)存
提高CPU性能(回收的快,業(yè)務(wù)邏輯產(chǎn)生對象的速度固定蛤育,垃圾回收越快喉前,內(nèi)存空間越大)
降低MixedGC觸發(fā)的閾值,讓MixedGC提早發(fā)生(默認(rèn)是45%)
問:生產(chǎn)環(huán)境中能夠隨隨便便的dump嗎秃诵? 小堆影響不大,大堆會有服務(wù)暫停或卡頓(加live可以緩解)槽卫,dump前會有FGC
問:常見的OOM問題有哪些? 棧 堆 MethodArea 直接內(nèi)存
如果JVM進(jìn)程靜悄悄退出怎么辦胰蝠?
-
JVM自身OOM導(dǎo)致
- heap dump on oom歼培,這種最容易解決
-
JVM自身故障
- -XX:ErrorFile=/var/log/hs_err_pid<pid>.log 超級復(fù)雜的文件 包括:crash線程信息 safepoint信息 鎖信息 native code cache , 編譯事件, gc相關(guān)記錄 jvm內(nèi)存映射 等等
-
被Linux OOM killer殺死
日志位于/var/log/messages
egrep -i 'killed process' /var/log/messages
-
硬件或內(nèi)核問題
- dmesg | grep java
找我!
如何排查直接內(nèi)存茸塞?
NMT打開 -- -XX:NativeMemoryTracking=detail
perf工具
gperftools
有哪些常用的日志分析工具躲庄?
gceasy
CPU暴增如何排查?
top -Hp jstack
arthas - dashboard thread thread XXXX
兩種情況:1:業(yè)務(wù)線程 2:GC線程 - GC日志
死鎖如何排查钾虐?
jstack 觀察線程情況
arthas - thread -b
參考資料
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp
JVM調(diào)優(yōu)參考文檔:https://docs.oracle.com/en/java/javase/13/gctuning/introduction-garbage-collection-tuning.html#GUID-8A443184-7E07-4B71-9777-4F12947C8184
http://www.reibang.com/p/507f7e0cc3a3 arthas常用命令
-
Arthas手冊:
啟動arthas java -jar arthas-boot.jar
綁定java進(jìn)程
dashboard命令觀察系統(tǒng)整體情況
help 查看幫助
help xx 查看具體命令幫助
-
jmap命令參考: http://www.reibang.com/p/507f7e0cc3a3
jmap -heap pid
jmap -histo pid
jmap -clstats pid
https://blog.csdn.net/chenssy/article/details/78271744 分析hotspot error file