前景提要:
GC相关参数:官方文档
- 查看虚拟机参数命令:jdk下java路径+ -XX:+PrintFlagsFinal -version | findstr "GC"
PS D:\project\JVM> D:\JAVA\JDK\bin\java -XX:+PrintFlagsFinal -version | findstr "GC"
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) Client VM (build 25.65-b01, mixed mode)
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 = 67108864 {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 = 0 {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 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 = false {product}
bool UseParallelOldGC = false {product}
bool UseSerialGC = false {product}
1.调优领域
- 内存
- 锁竞争
- CPU占用
- IO
- GC
2.确定目标
低延迟/高吞吐量? 选择合适的GC
- CMS G1 ZGC
- ParallelGC
- Zing
3.最快的GC是不发生GC
首先排除减少因为自身编写的代码而引发的内存问题:
1.查看Full GC前后的内存占用,考虑以下几个问题:
是否是自己程序写的有问题:
如:resultSet = statement.executeQuery("select * from 大表");//查询的数据一下太多了导致空间不足
2.是不是自己定义的对象太臃肿:定义了好多无效变量
2.1对象图
2.2注意对象大小,Java中new一个Object或者包装类型对象,至少16字节
3.是否存在内存泄漏?
3.1 static Map map = HashMap()
,当我们不断的向静态的map中新增对象且不移除,就可能造成内存吃紧。这时可以使用软引用,弱引用来解决上面的问题,因为它们可以在内存吃紧时,被定期回收。也可以使用第三方的缓存中间件(Redis)来存储上面的map中的数据。
4.新生代调优
新生代的特点:
4.1 当我们new
一个对象时,会先在伊甸园中进行分配,所有的new
操作分配内存都是非常廉价且速度极快的。
- TLAB(Thread-Location Allocation Buffer):当我们
new
一个对象时,会先检查TLAB缓冲区中是否有可用内存,如果有则优先在TLAB中进行对象分配。这是一块私有的区域不同的线程不是不能共享的,这样多个线程同时分配时也不会产生干扰
4.2 死亡对象回收的代价为零(因为采用的时复制算法所以幸存对象都在幸存区to区域中)
4.3大部分对象用过即死(朝生夕死)
4.4MInor GC 所用时间远小于Full GC
问题:新生代的内存越大越好吗?
答:不是,1.新生代内存太小:频繁触发Minor GC,会 STW,会使得吞吐量下降。2.新生代内存太大:老年代内存占比有所降低,会更频繁地触发Full GC。而且触发Minor GC时,清理新生代所花费的时间会更长。建议:新生代内存设置为能容纳 并发量*(请求-响应)
的数据为宜。
5.幸存区调优
5.1 幸存区最大能够保存 当前活跃对象+需要晋升的对象
5.2 晋升阈值配置得当,让长时间存活的对象尽快晋升。(如果不能竟早晋升则会留在幸存区复制来复制去,影响速度)
下图中这行数据是某个年龄现在所占空间,
后面这行是累计所占空间。
6. 老年代调优
以CMS为例:
- CMS的老年代内存越大越好。
- 先尝试不做调优,如果没有 Full GC 那么说明当前系统暂时不需要优化,否则,就先尝试调优新生代。
- 观察发生Full GC 时老年代的内存占用,将老年代内存预设调大 1/4 ~ 1/3。
- -XX:CMSInitiatingOccupancyFraction=percent(老年代占用达到老年代多少时使用CMS)
7.案例
- 当Full GC 和 Minor GC 调用频繁。(增加晋升阈值增加新生代空间大小)
- 当请求高峰期发生Full GC,单次暂停时间特别长(CMS)(可以观察GC日志如果是重新标记阶段时间过长可以尝试在重新标记前将新生代进行一次GC这样可以减少重新标记时间长度)
- 在老年代充裕的情况下,发生Full GC (1.7)(1.7没有使用元空间即系统空间,可能是空间不足相比于1.8使用系统空间而言)