JVM学习笔记
4 GC调优
- 掌握GC相关的JVM参数,会基本的空间调整
- 掌握相关工具
- 重点:调优与应用和环境有关,没有统一的规则
查看虚拟机运行参数
“jdk下bin目录下java命令的绝对地址” -XX:+PrintFlagFinal -version | findstr “GC”
我的是 “E:\Java\jdk1.8.0_191\bin\java” -XX:+PrintFlagsFinal -version | findstr "GC"
你的呢,弟弟。
命令行中输入上述命令
uintx AdaptiveSizeMajorGCDecayTimeScale = 10 {product}
uintx AutoGCSelectPauseMillis = 5000 {product}
bool BindGCTaskThreadsToCPUs = false {product}
uintx CMSFullGCsBeforeCompaction = 0 {product}
uintx ConcGCThreads = 0 {product}
bool DisableExplicitGC = false {product}
bool ExplicitGCInvokesConcurrent = false {product}
bool ExplicitGCInvokesConcurrentAndUnloadsClasses = false {product}
uintx G1MixedGCCountTarget = 8 {product}
uintx GCDrainStackTargetSize = 64 {product}
uintx GCHeapFreeLimit = 2 {product}
uintx GCLockerEdenExpansionPercent = 5 {product}
bool GCLockerInvokesConcurrent = false {product}
uintx GCLogFileSize = 8192 {product}
uintx GCPauseIntervalMillis = 0 {product}
uintx GCTaskTimeStampEntries = 200 {product}
uintx GCTimeLimit = 98 {product}
uintx GCTimeRatio = 99 {product}
bool HeapDumpAfterFullGC = false {manageable}
bool HeapDumpBeforeFullGC = false {manageable}
uintx HeapSizePerGCThread = 87241520 {product}
uintx MaxGCMinorPauseMillis = 4294967295 {product}
uintx MaxGCPauseMillis = 4294967295 {product}
uintx NumberOfGCLogFiles = 0 {product}
intx ParGCArrayScanChunk = 50 {product}
uintx ParGCDesiredObjsFromOverflowList = 20 {product}
bool ParGCTrimOverflow = true {product}
bool ParGCUseLocalOverflow = false {product}
uintx ParallelGCBufferWastePct = 10 {product}
uintx ParallelGCThreads = 4 {product}
bool ParallelGCVerbose = false {product}
bool PrintClassHistogramAfterFullGC = false {manageable}
bool PrintClassHistogramBeforeFullGC = false {manageable}
bool PrintGC = false {manageable}
bool PrintGCApplicationConcurrentTime = false {product}
bool PrintGCApplicationStoppedTime = false {product}
bool PrintGCCause = true {product}
bool PrintGCDateStamps = false {manageable}
bool PrintGCDetails = false {manageable}
bool PrintGCID = false {manageable}
bool PrintGCTaskTimeStamps = false {product}
bool PrintGCTimeStamps = false {manageable}
bool PrintHeapAtGC = false {product rw}
bool PrintHeapAtGCExtended = false {product rw}
bool PrintJNIGCStalls = false {product}
bool PrintParallelOldGCPhaseTimes = false {product}
bool PrintReferenceGC = false {product}
bool ScavengeBeforeFullGC = true {product}
bool TraceDynamicGCThreads = false {product}
bool TraceParallelOldGCTasks = false {product}
bool UseAdaptiveGCBoundary = false {product}
bool UseAdaptiveSizeDecayMajorGCCost = true {product}
bool UseAdaptiveSizePolicyWithSystemGC = false {product}
bool UseAutoGCSelectPolicy = false {product}
bool UseConcMarkSweepGC = false {product}
bool UseDynamicNumberOfGCThreads = false {product}
bool UseG1GC = false {product}
bool UseGCLogFileRotation = false {product}
bool UseGCOverheadLimit = true {product}
bool UseGCTaskAffinity = false {product}
bool UseMaximumCompactionOnSystemGC = true {product}
bool UseParNewGC = false {product}
bool UseParallelGC := true {product}
bool UseParallelOldGC = true {product}
bool UseSerialGC = false {product}
java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)
04_01 调优领域
- 内存
- 锁竞争
- cpu占用
- io
04_02 调优目标
- 低延迟还是高吞吐量,选择合适收集器
- CMS G1 ZGC(超低延迟)
- Parallel GC
04_03 最快的GC是不发生GC
- 查看FULL GC前后的内存占用,考虑下面几个问题
- 数据是不是太多
- result = statement.Query(“select * from bigTable limit n”);
- 数据表示太臃肿
- 对象图
- 对象大小 16字节 Integer 24 int 4(所以一般用基本类型)
- 是否存在内存泄漏
- static Map map 不断加入对象,强引用不得回收
- 软
- 弱
- 第三方缓存产品 redis等
- 数据是不是太多
04_04 新生代调优
- 新生代特点
- 所有new操作分配的内存都是廉价的
- TLAB thread local allocation buffer
- 死亡对象回收代价是0
- 垃圾回收将Eden和From中存活的对象复制到To中,剩下的垃圾对象直接全部删除,代价很小。
- 大部分对象用过即死
- Minor GC比Full GC 时间小很多。
- 所有new操作分配的内存都是廉价的
新生代是否越大越好
- (1/4-1/2)堆内存的大小
- 新生代过小,会频繁触发Minor GC
- 新生代过大,老年代相应的变小,FULL GC 门槛变低
- 在新生代变大的过程中,吞吐量首先是增长的,之后会下降。
- 新生代对象大多数都是用过即死,存活的对象极少,在新生代内存增大后,新生代的复制算法也不会受太多影响。
- 新生代能够容纳所有【并发量*(请求/响应)】的数据。
- 如果一次请求产生512k的对象,同一时间有1000个并发用户,则要保证新生代要能够存储512M的对象。
幸存区大到能保留(当前活跃对象以及需要晋升的对象)
- 这样能保证用不着的垃圾对象下次就能被回收
- 如果新存区不够存放,那么对象就会被转移到老年代,回收时间就会增加
晋升阈值配置得当,使长时间存活对象尽快晋升
- -XX:MaxTenuringThreshold=threshold 配置阈值
- -XX:+PrintTenuringDistribution 打印晋升细节
04_05 老年代调优
以cms为例。
- 老年代内存越大越好
- 先尝试不要做调优,如果没有FULL GC,那么已经满足需求,否则先尝试新生代调优
- 观察发生FULL GC时老年代的内存占用,将老年代的内存提高1/4-1/3
- -XX:CMSInitialOccupancyFraction = percent 推荐设置为70-80
04_06 案例
- 案例一:FULL GC和Minor GC频繁
首先分析可能原因,先做新生代调优,新生代内存过小,对象放不下直接进入老年代,不仅Minor GC频繁,老年代中也会存入大量垃圾对象,FULL GC 也会频繁发生。
所以,适当增大新生代内存大小,使得Eden可以存下新生的多个对象,不会过于频繁触发Minor GC,幸存区存下幸存对象能够使幸存对象在新存区中保存,不会过早进入老年代,老年代内存占用减轻。
- 案例二:请求高峰期发生FULL GC,单次暂停时间过长(CMS)
分析:请求高峰,并发用户很多,产生的新对象很多,堆中对象数目较大。CMS中重新标记会扫描整个堆内存来标记对象,所以会耗用大量时间。
调优:-XX:+CMSScavengeBeforeRemark 设置在重新标记前对新生代进行一次垃圾清理,会大大减少重新标记的时间。
- 案例三 老年代充裕情况下,发生FULL GC(cms jdk1.7)
在jdk1.7及以前,方法区以永久代方式实现,永久代内存不足时,也会发生FULL GC ,增加
jdk1.8及以后,利用元空间实现,使用的是系统内存,内存充裕,很少会触发FULL GC。
5 类加载和字节码技术
01_类文件结构
01_1 魔数
0-3字节,表示它是否是【class】类型的文件
0000000 ca fe ba be 00 00 00 34 00 23 0a 00 06 00 15 09
01_2 版本
4-7字节,表示类的版本 00 34(52) 表示是java8
0000000 ca fe ba be 00 00 00 34 00 23 0a 00 06 00 15 09
01_3 常量池
- 8-9字节,表示常量池长度, 00 23(35) 表示常量池#1-#34项,注意#0项不计入,也没有值。
0000000 ca fe ba be 00 00 00 34 00 23 0a 00 06 00 15 09 - 第#1项0a表示一个Method信息,00 06和00 15(21)表示他引用了常量池中#6和#21项来获得这个方法的【所属类】和【方法名】。
0000000 ca fe ba be 00 00 00 34 00 23 0a 00 06 00 15 09- 0a(16)=10,查表可知是方法引用信息。
-
第#2项09表示一个Filed信息,00 16(22)和00 17(23) 表示它引用了常量池中#22和#23来获得这个成员变量的【所属类】和【成员变量名】
0000000 ca fe ba be 00 00 00 34 00 23 0a 00 06 00 15 09
0000020 00 16 00 17 08 00 18 0a 00 19 00 1a 07 00 1b 07 -
第#3项08表示一个字符串常量名称,00 18(24)表示它引用了常量中中#24项
0000020 00 16 00 17 08 00 18 0a 00 19 00 1a 07 00 1b 07 -
第#4项0a表示一个Method信息00 19(25)和00 1a(26)表示它引用了常量池中#25和#26项来获得这个类的【所属类】和【方法名】
0000020 00 16 00 17 08 00 18 0a 00 19 00 1a 07 00 1b 07 -
第#5项07表示一个class信息,00 1b(27)表示它引用了常量池中的#27项
0000020 00 16 00 17 08 00 18 0a 00 19 00 1a 07 00 1b 07 -
第#6项07表示一个class信息,00 1c(28)表示它引用了常量池中的#28项
0000020 00 16 00 17 08 00 18 0a 00 19 00 1a 07 00 1b 07
0000040 00 1c 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29
01_4 访问标识和继承信息
01_5 Field信息
01_6 Method信息
算了,具体16进制字节码就不说了,太多了,反编译好用点,javap -c -l name.class
01_7 附加属性
- 官方文档