GC问题的排查流程主要包括观察GC日志、分析内存使用情况、寻找GC导致的性能问题、调整GC参数、使用垃圾收集器分析工具和进行压力测试和性能调优。根据具体情况,可能需要结合多种方法和工具来诊断和解决GC问题。
也可以通过 使用jmap命令查某时刻的JVM堆信息,查看占用比较高的对象
对象首次创建会被放置在新生代的eden区
对象进入老年代主要有下面三种方式:
这个默认值是根据实践经验和性能测试得出的,可以尽可能的的保证垃圾回收效率的前提下减少移动到老年代的对象数量;从而减少Full gc
最小是1,不可以设置为负数或0
最大值是15,原因是对象的GC年龄存储在对象头里,分配4bit存储,转换为二进制就是15.
由于程序计数器、栈、本地方法栈都是线程独享,其占用的内存是随线程结束而回收。而Java堆和方法区则不同,线程共享,是GC的所关注的部分。
给对象添加一个引用计数器,当有一个地方引用对象是计数器加1,当引用失效是计数器减1,当该对象的计数器为0时表示可以回收。
从GC Roots对象作为起点向下搜索,当一个对象不在GC Roots的引用链路中时,该对象可以回收。
GC Roots对象包含:方法区静态属性引用的对象、栈中引用的对象、本地方法栈中Native方法引用的对象、常量引用的对象。
从GC Roots开始,把所有可以搜索得到的对象标记为存活对象,固定可作为GC Roots的对象包括以下几种:·
v 在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。·
v 在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。·在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。
v 在本地方法栈中Native方法引用的对象。
v Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。
v 所有被同步锁(synchronized关键字)持有的对象。
新生代收集器:
老年代收集器:
G1是一个独立的收集器不依。ZGC是目前JDK 11的实验收集器。
低停顿的老年代垃圾回收器,通过初始标记,并发标记两个阶段来实现垃圾回收,。
CMS都有哪些问题?
解决老年代碎片化问题的办法
CMS在进行一定次数的Full GC(标记清除)的时候进行一次标记整理算法,
-XX:UseCMSCompactAtFullCollection -XX:CMSFullGCBeforeCompaction=5
G1是JDK8 开始有在JDK9作为默认垃圾回收器。
其他:
JVM最多可以有2048个Region。一般Region大小等于堆大小除以2048,比如堆大小为4096M,则Region大小为2M。
G1收集器通过使用多线程和并发标记清除阶段来实现可预测停顿。
G1将堆划分为多个大小相等的Region,每个Region的大小可以是1MB到32MB之间。Region的大小由用户在启动JVM时通过参数进行配置。
G1的堆结构由多个类型的Region组成,包括:
G1收集器使用了多个Region之间的引用关系和各个Region之间的协作,来实现高效的并发标记和回收,以及垃圾回收的可预测性。
G1(Garbage-First)垃圾回收器提供了一些JVM参数配置,用于调整G1垃圾回收器的行为和性能。以下是一些常用的G1相关的JVM参数配置:
-XX:+UseG1GC
:启用G1垃圾回收器。-XX:MaxGCPauseMillis=
:设置期望的最大垃圾回收停顿时间(毫秒)。G1会尽量控制垃圾回收停顿时间不超过该值。-XX:G1HeapRegionSize=
:设置G1堆区的区域大小。默认值为堆大小的1/2000,一般不需要手动设置。-XX:ParallelGCThreads=
:设置并行垃圾回收的线程数。-XX:ConcGCThreads=
:设置并发标记阶段的线程数。-XX:InitiatingHeapOccupancyPercent=
:设置触发混合收集的堆占用百分比阈值。当堆占用达到该阈值时,G1会触发混合收集。-XX:G1ReservePercent=
:设置G1堆区的保留空间百分比。默认值为10,表示G1会保留10%的堆空间不被回收。-XX:G1HeapWastePercent=
:设置G1堆区的废弃空间百分比阈值。当堆区的废弃空间超过该阈值时,G1会执行回收操作。-XX:G1MixedGCLiveThresholdPercent=
:设置混合收集过程中存活对象的阈值百分比。默认值为65,表示混合收集过程中如果存活对象超过65%,则会触发Full GC。这些参数可以根据具体的应用场景和性能需求进行调整。注意,在使用G1垃圾回收器时,不需要手动设置很多参数,因为G1会根据堆的大小和系统配置自动调整一些参数。建议在需要微调性能时再考虑调整这些参数。
收集过程
优缺点:
在回收阶段,将标记对象越过堆的空闲区移动到堆的另一端,所有被移动的对象的引用也会被更新指向新的位置。
通过目标参数-XX:MaxGCPauseMills和-XX:GCTimeRatio,调整新生代空间大小,来降低GC触发的频率。
并行收集器适合对吞吐量要求远远高于延迟要求的场景,并且在满足最差延时的情况下,并行收集器将提供最佳的吞吐量。
如果系统对吞吐量要求比较高,可以优先考虑新生代 Parallel Scavenge
和年老代 Parallel Old 收集器的搭配策略。
CMS(Concurrent Mark Sweep)收集器具有以下特点:
CMS执行过程:
内存碎片问题:
-XX:UseCMSCoimpactAtFullCollection 默认打开,在cms fgc后会STW进行碎片整理。
-XX:CMSFullGCsBeforeCompaction=0 默认0,多少次fgc后进行一次碎片整理,0每次fgc后都整理。
concurrent mode failure 问题:
CMS并发处理中,年轻代移到到老年代内存不够,老年代的垃圾收集器从CMS退化为Serial Old,所有应用线程被暂停。
-XX:CMSInitiatingOccupancyFraction=N调小,并启用碎片整理
CMS 也有一些缺点,其中最大的问题就是老年代内存碎片问题(因为不压缩),
在某些情况下 GC 会造成不可预测的暂停时间,特别是堆内存较大的情况下。
G1收集器概述
JDK1.7后全新的JVM垃圾收集器G1收集器, 目标用于取代CMS收集器。
2. G1相比较CMS的改进
3. CMS和G1的区别
4. G1收集器的应用场景
G1垃圾收集算法主要应用在多CPU大内存的服务中,在满足高吞吐量的同时,尽可能的满足垃圾回收时的暂停时间。
就目前而言、CMS还是默认首选的GC策略、可能在以下场景下G1更适合:
Garbage first 垃圾收集器是目前垃圾收集器理论发展的最前沿成果,相比与 CMS 收集器,G1 收
集器两个最突出的改进是:
G1 收集器避免全区域垃圾收集,它把堆内存划分为大小固定的几个独立区域,并且跟踪这些区域
的垃圾收集进度,同时在后台维护一个优先级列表,每次根据所允许的收集时间,优先回收垃圾
最多的区域。区域划分和优先级区域回收机制,确保 G1 收集器可以在有限时间获得最高的垃圾收
集效率。
这些表象一般伴随着频繁的垃圾回收,或者OOM。
堆内存参数
-Xms512m |
初始堆大小 默认值:若未设置,初始值将是老年代和年轻代分配制内存之和 |
-Xmx1024m |
堆内存最大值。 |
年轻代内存相关参数
-Xmn512m |
新生代的初始值及最大值。 默认值:堆内存的1/4(已经分配的堆内存的1/4)。 |
-XX:NewSize=512m |
设置新生代的初始值。 |
-XX:MaxNewSize=512m |
设置新生代的最大值。 |
-XX:NewRatio=8 |
老年代和年轻代的比例。 比如:-XX:NewRatio=8 表示:老年代内存:年轻代内存=8:1 |
-XX:SurvivorRatio=8 |
新生代和存活区的比例 -XX:SurvivorRatio=8 表示存活区:新生代=1:8 =》新生代占年轻代的8/10,每个存活区各占年轻代的1/10 |
元空间参数
-XX:MetaspaceSize |
初始元空间大小 达到该值就会触发垃圾收集进行类型卸载 |
-XX:MaxMetaspaceSize=256m |
设置元空间的最大值,默认是没有上限的,也就是说你的系统内存上限是多少它就是多少。 |
一般 应用的响应慢、CPU占用高,gc次数高,发生了OOM,排除是代码问题后,是需要调优了。
1.如果是原生内存不足,可以通过 jmap -heap pid 查看 jvm 内存分配
1.定位需要调优的位置(首先定位内存占用在那里,是否是内存泄漏)
2.定位到问题后针对问题调整参数
比如:堆的大小,新生代,老生代的比例,减少fulklgc
首先在启动程序的时候
-XX:+PrintGC:输出GC日志
-XX:+PrintGCDetails:输出GC的详细日志
-XX:+PrintGCTimeStamps:输出GC的时间戳(以基准时间的形式)
-XX:+PrintGCDateStamps:输出GC的时间戳(以日期的形式,如2018-08-29T19:22:48.741-0800)
-XX:+PrintHeapAtGC:在进行GC的前后打印出堆的信息
-Xloggc:gc.log:日志文件的输出路径
-XX:+HeapDumpOnOutOfMemoryError 发生内存溢出时生成heapdump文件
-XX:+HeapDumpBeforeFullGC 发生Full gc前生成heapdump文件
-XX:HeapDumpPath:指定heapdump输出路径
总结:
若是代码问题可通过版本控制工具找到本期变更的代码,优化代码
若非代码问题,可适当增加堆内存大小、新生代老年代的大小与比例 , 适当增大新生代内存大小。
jstat 是 jdk bin 下自带工具,最多的是用来统计gc相关信息,使用步骤如下。
jvm-demo.jar
(进程号27164)的gc信息,并且每隔3秒统计一次,可以执行以下命令jstat -gcutil 27164 3000
主要关注以下几个。
若要进一步查看上一次GC信息
jstat -gccause 27146 3000
使用步骤
jvm-demo.jar
(进程号27164)的信息,并且每隔3秒统计一次,可以执行以下命令jmap -heap 2865
输出内容示例:
Attaching to process ID 27146, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.144-b01
using thread-local object allocation.
Mark Sweep Compact GC
#堆相关的配置信息
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 104857600 (100.0MB)
NewSize = 10485760 (10.0MB)
MaxNewSize = 34930688 (33.3125MB)
OldSize = 20971520 (20.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
#堆占用相关的配置信息
Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 12517376 (11.9375MB)
used = 10708296 (10.212226867675781MB)
free = 1809080 (1.7252731323242188MB)
85.54745020042539% used
Eden Space:
capacity = 11141120 (10.625MB)
used = 10708272 (10.212203979492188MB)
free = 432848 (0.4127960205078125MB)
96.11486098345588% used
From Space:
capacity = 1376256 (1.3125MB)
used = 24 (2.288818359375E-5MB)
free = 1376232 (1.3124771118164062MB)
0.0017438616071428572% used
To Space:
capacity = 1376256 (1.3125MB)
used = 0 (0.0MB)
free = 1376256 (1.3125MB)
0.0% used
tenured generation:
capacity = 27684864 (26.40234375MB)
used = 27096504 (25.84123992919922MB)
free = 588360 (0.5611038208007812MB)
97.87479541167332% used
15431 interned Strings occupying 2044328 bytes.
JDK内置的命令行:jps(查看jvm进程信息)、jstat(监视jvm运行状态的,比如gc情况、jvm内存情况、类加载情况等)、jinfo(查看jvm参数的,也可动态调整)、jmap(生成dump文件的,在dump的时候会影响线上服务)、jhat(分析dump的,但是一般都将dump导出放到mat上分析)、jstack(查看线程的)。
JDK内置的可视化界面:JConsole、JVisualVM,这两个在QA环境压测的时候很有用。
阿里巴巴开源的arthas:神器,线上调优很方便,安装和显示效果都很友好
可以查看层级关系的工具
ibm的was服务器产生的dump文件,要用他特有的jar包才可以看。
使用ha456.jar 查看dump文件。
java –Xmx5g -jar ha456.jar
链接:百度网盘 请输入提取码 密码:5vp4
jmap -dump:format=b,file=文件名 [pid]^C
类加载设置
-XX:+TraceClassLoading:类加载日志
-XX:+TraceClassUnloading:类卸载日志
堆设置
-Xms:初始堆大小
-Xmx:最大堆大小
-XX:NewSize=n:设置年轻代大小
-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4
-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
-XX:MaxPermSize=n:设置持久代大小
收集器设置
-XX:+UseSerialGC:设置串行收集器
-XX:+UseParallelGC:设置并行收集器
-XX:+UseParalledlOldGC:设置并行年老代收集
-XX:+UseConcMarkSweepGC:设置并发收集器
垃圾回收统计信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
并行收集器设置
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)
并发收集器设置
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。
分类 |
参数 |
说明 |
标准参数 |
-server |
jvm使用server模式,默认该模式,特点启动慢、运行性能和内存管理效率很高,适用生产环境。 |
-client |
jvm使用client模式,特点启动快、运行性能和内存管理效率不高,适用开发调试。 |
|
-Dproperty=value |
设置系统属性,可用System.getProperty(“property”)获取,如果value中有空格,则需要用双引号将该值括起来,如-Dname=”space string”,该参数通常用于设置系统级全局变量值 |
|
-verbose:gc |
表示输出虚拟机中GC的详细情况 |
|
堆内存 |
-Xms2g |
jvm内存(堆内存)启动初始值 默认是物理内存的1/64 |
-Xmx3g |
jvm内存(堆内存)最大值 默认是物理内存的1/4 |
|
-Xmn1g |
年轻代大小 |
|
栈内存 |
-Xss1m |
每个线程java虚拟机栈大小 |
-Xoss128k |
本地方法栈大小 HotSpot不区分虚拟机栈和本地方法栈,该参数无效 |
|
内存分配 |
-XX:PermSize=48m |
设置永久代初始大小 默认20.75M |
-XX:MaxPermSize=128m |
设置永久代最大可分配空间 32位机器默认64M 64位机器默认82M |
|
-XX:NewRatio=4 |
表示设置年轻代(包括Eden和两个Survivor区)/老年代 的大小比值为1:4,这意味着年轻代占整个堆的1/5 |
|
-XX:SurvivorRatio=8 |
表示设置2个Survivor区:1个Eden区的大小比值为2:8,这意味着Survivor区占整个年轻代的1/5,这个参数默认为8 |
|
进入老年代 |
-XX:PretenureSizeThreshold=3145728 |
表示对象大于3145728(3M)时直接进入老年代分配,这里只能以字节作为单位 |
-XX:MaxTenuringThreshold=1 |
表示对象年龄大于1,自动进入老年代,如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象在年轻代的存活时间,增加在年轻代被回收的概率。最大15 |
|
-XX:TargetSurvivorRatio |
默认50,动态年龄判断 年龄1、2...n累计到达S区50%,年龄n及以上进入老年代 |
|
参数配置 |
-Xloggc:filePath |
配置gc日志路径 |
-XX:+PrintGCDetails |
打印详细的gc日志 |
|
-XX:+PrintGCTimeStamps |
打印gc发生的时间 |
|
-XX:+TraceClassLoading |
表示查看类的加载信息 |
|
-XX:+TraceClassUnLoading |
表示查看类的卸载信息 |
|
-XX:+HeapDumpOnOutOfMemoryError |
表示可以让虚拟机在出现内存溢出异常时Dump出当前的堆内存转储快照 |
|
-XX:HeapDumpPath |
内存溢出异常时Dump出堆内存快照路径 |
|
-XX:CompileThreshold=1000 |
表示一个方法被调用1000次之后,会被认为是热点代码,并触发即时编译 |
|
-XX:+PrintHeapAtGC |
表示可以看到每次GC前后堆内存布局 |
|
-XX:+PrintTLAB |
表示可以看到TLAB的使用情况 |
|
-XX:+UseSpining |
开启自旋锁 |
|
-XX:PreBlockSpin |
更改自旋锁的自旋次数,使用这个参数必须先开启自旋锁 |
|
-XX:DisableExplicitGC |
禁止显示执行GC,即禁止代码触发GC(System.gc();) |
|
调优参数 |
-XX:+ExplicitGCInvokesConcurrent |
命令JVM无论什么时候调用系统GC,都执行CMS GC,而不是Full GC。 |
-XX:+ParallelRefProcEnabled |
并行处理Reference,加快处理速度,缩短耗时 |
|
-XX:UseCMSCompactAtFullCollection |
full gc压缩 默认true开启 |
|
-XX:CMSFullGCsBeforeCompaction |
多少次full gc做压缩,默认0,每次full gc后压缩碎片 |
|
-XX:CMSInitiatingOccupancyFraction=92 |
是指设定CMS在对内存占用率达到92%的时候开始GC(因为CMS会有浮动垃圾,所以一般都较早启动GC) |
|
-XX:+UseCMSInitiatingOccupancyOnly |
只是用设定的回收阈值(上面指定的92%),如果不指定,JVM仅在第一次使用设定值,后续则自动调整. |
|
-XX:+CMSScavengeBeforeRemark |
在CMS GC重新标记前启动一次ygc,目的在于减少old gen对ygc gen的引用,降低remark时的开销(一般CMS的GC耗时 80%都在remark阶段) |
|
-XX:+CMSParallelInitialMarkEnabled |
在CMS垃圾回收器的“初始标记”阶段开启多线程并发执行 |
|
垃圾回收器 |
-XX:+UseG1GC |
表示让JVM使用G1垃圾收集器 |
-XX:+UseSerialGC |
表示使用jvm的串行垃圾回收机制,该机制适用于单核cpu的环境下 |
|
-XX:+UseParallelGC |
表示使用jvm的并行垃圾回收机制,该机制适合用于多cpu机制,同时对响应时间无强硬要求的环境下,使用-XX:ParallelGCThreads=设置并行垃圾回收的线程数,此值可以设置与机器处理器数量相等。 |
|
-XX:+UseParallelOldGC |
表示年老代使用并行的垃圾回收机制 |
|
-XX:+UseConcMarkSweepGC |
表示使用并发模式的垃圾回收机制,该模式适用于对响应时间要求高,具有多cpu的环境下 |
|
G1参数 |
-XX:MaxGCPauseMillis=100 |
设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值。 |
-XX:+UseAdaptiveSizePolicy |
设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低响应时间或者收集频率等,此值建议使用并行收集器时,一直打开 |
|
-XX:G1HeapRegionSize |
指定Region大小(必须是2的倍数,1M、2M、4M到32M。一般自己计算即可) |
|
-XX:G1NewSizePercent |
新生代初始内存,默认为堆内存的5% |
|
-XX:G1MaxNewSizePercent |
新生代最高内存,默认为堆内存的60% |
|
-XX:InitiatingHeapOccupancyPercent |
到达老年代占据堆内存的百分比时,会触发新生代和老年代的混合垃圾回收,默认45% |
|
-XX:G1MixedGCCountTarget |
多次混合回收,默认8次 |
|
-XX:G1HeapWastePercent |
停止结束混合回收条件,堆内存有5%空闲Region 默认5 |
|
-XX:G1MixedGCLiveThresholdPercent |
每个Region空间存活对象低于85%时才会回收,默认85 |
|
Metaspace |
-XX:MetaspaceSize |
是分配给类元数据空间(以字节计)的初始大小(Oracle逻辑存储上的初始高水位,the initial high-water-mark ),此值为估计值。MetaspaceSize的值设置的过大会延长垃圾回收时间。垃圾回收过后,引起下一次垃圾回收的类元数据空间的大小可能会变大。 |
-XX:MaxMetaspaceSize |
是分配给类元数据空间的最大值,超过此值就会触发Full GC,此值默认没有限制,但应取决于系统内存的大小。JVM会动态地改变此值。 |
|
-XX:MinMetaspaceFreeRatio |
表示一次GC以后,为了避免增加元数据空间的大小,空闲的类元数据的容量的最小比例,不够就会导致垃圾回收。 |
|
-XX:MaxMetaspaceFreeRatio |
表示一次GC以后,为了避免增加元数据空间的大小,空闲的类元数据的容量的最大比例,不够就会导致垃圾回收。 |