JVM
一、JVM常用参数
java -Xms2048M -Xmx2048M -Xmn1024M -Xss512K -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -jar XXX.jar
| 含义 | 参数 | 备注 |
|---|---|---|
| 每个线程的栈大小 | -Xss | |
| 堆初始大小 | -Xms | 堆的初始可用大小,默认为物理内存的1/64 |
| 堆最大大小 | -Xmx或-XX:MaxHeapSize=size | 为了避免在运行时频繁调整Heap的大小,通常-Xms与-Xmx的值设成一样 |
| -XX:MinHeapFreeRation | 当空余堆内存小于40%时,JVM会增大堆内存到-Xmx指定的大小,可以使用此参数来调整这个比例 | |
| -XX:MaxHeapFreeRation | 当空余堆内存大于70%时,JVM会减小堆内存的大小到-Xms指定的大小,可以使用此参数来调整这个比例 | |
| 新生代大小 | -Xmn 或 (-XX:NewSize=size -XX:MaxNewSize=size) | -XX:NewSize=size设置新生代初始大小,-XX:MaxNewSize=size设置新生代最大大小,而-Xmn相当于同时指定初始和最大 |
| 幸存区比例(动态) | -XX:InitialSurvivorRatio=ratio -XX:+UseAdaptiveSizePolicy | 某些垃圾收集器可以将幸存区比例设置为一个动态值 |
| 幸存区比例 | -XX:survivorRatio=ratio | 默认值为8,代表eden区占新生代比重为80%,其余from和to区分别10% |
| 晋升阈值 | -XX:maxTenuringThreshold=threshold | 该值允许的最大值也和垃圾收集器有关 |
| 打印晋升详情 | -XX:+PrintTenuringDistribution | 如果对象发生晋升,将会被打印出来 |
| GC详情 | -XX:+PrintGCDetails -verbose:gc | 发生GC时,打印详情 |
| FullGC前MinorGC | -XX:+ScavengeBeforeFullGC | |
| 元空间最大值 | -XX:MaxMetaspaceSize=N | 默认-1, 即不限制,或者说只受限于本地内存大小 |
| -XX:MetaspaceSize=N | 指定元空间触发Fullgc的初始阈值(元空间无固定初始大小), 以字节为单位,默认是21M左右 | |
| 串池最大桶数量 | -XX:StringTableSize=200000 | 将串池中桶的个数调整为20万个(StringTable的数据结构为HashTable,使用数组+链表来存储数据,桶的个数实际就是数组的大小) |
| 打印串池信息 | -XX:PrintStringTableStatistics | |
| 禁用显式的GC | -XX:+DisableExplicitGC | 即让 System.gc() 失效,但这个参数可能会影响直接内存的回收,直接内存只能等待真正的GC时才会回收,此时,可以手动的回收直接内存:参考UnSafe.freeMemory(addr),另注:System.gc()触发的是full GC |
| 使用串行垃圾收集器 | -XX:+UseSerialGC | Serial(新生代-复制算法) + SerialOld(老年代:标记整理) |
二、线程运行诊断
1、cpu占用过高
- 用top定位哪个进程对cpu占用过高
- ps H -eo pid,tid,%cpu | grep 进程id(用ps命令进一步定位是哪个线程引起的cpu占用过高)
- jstack 进程id(可以根据线程id找到有问题的线程,进一步定位到有问题的源代码行数)
三、垃圾回收
Memory Analyzer (MAT)
专业的Java堆分析工具,可以帮助找到内存泄漏,节约内存占用
1、如何判断对象可以回收
- 引用计数法
- 可达性分析算法,GC Root:
- 系统核心类
- 本地方法中引用的java对象
- 被同步锁锁住的对象
- 活动线程所使用的对象(即:栈帧局部变量所引用的对象)
2、五种引用
- 强引用:只有所有的GC Roots对象都不通过强引用引用该对象,该对象才能被垃圾回收
- 软引用(SoftReference):当垃圾回收发生时,若发现回收后内存仍然不足,会回收软引用对象
鉴于软应用本身也会占用内存,可以配合引用队列来释放软引用自身 - 弱引用(WeekReference):当垃圾回收发生时,弱引用关联的对象一定会被回收
- 虚引用(PhantomReference):必须配合引用队列使用,主要配合 ByteBuffer 使用,被虚引用引用的对象回收时,会将虚引用入队,由Reference Handler线程调用虚引用相关方法释放直接内存
- 终结器引用(FinalReference):无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用入队(被引用对象暂时没有被回收),再由Finalizer线程通过终结器引用找到被引用对象并调用它的finalize方法,第二次GC时才能回收被引用对象
3、垃圾回收算法
- 标记清除:对可回收的对象做标记,随之清除其所占内存(并不是真正的清除,只将该内存的起始-结束地址记录到可用空间的记录表),该算法会造成内存碎片,影响大对象的存储
- 标记整理:对可回收的对象做标记,并将后面存活的对象移动到该对象地址所在区域,涉及到对象的移动,且由于对象的地址发生改变,引用该对象的局部变量等也需要做相应修改,比较耗时
- 复制:复制算法将空间划分为两个区域,将所有存活的对象从from区域复制到to区域,然后清除from区域的内存,将两个区域交换。
4、分代垃圾回收(针对不同的区域采用不同的回收算法)
- 新生代:针对对象存活期短,每次GC后存活的对象较少,使用复制算法,同时将新生代划分为三个区域eden,from,to,并调整各个区域的内存比例(默认8 1 1),以求达到最大空间利用效率
- 老年代:标记清除算法,或 标记整理算法
- 对象首先分配在eden区
- eden区空间不足时,触发minor gc,eden和from存活的对象使用copy算法复制到to区,存活的对象年龄+1,清除eden和from区的死亡对象,随后交换from区和to区(只是from和to这两个指针对各自区域的指向发生交换,两个内存区域实际未动)
- minor gc 会引发 stop the world,暂停所有用户线程:新生代垃圾回收使用复制算法,期间对象的地址会发生变化,如果不暂停用户线程,会发生混乱
- 新生代对象年龄超过阈值时,晋升到老年代,默认最大阈值为15(每个对象中使用4个bit位记录其年龄)
- 在新生代对象要晋升到老年代时,晋升进入老年代对象的大小 > 老年代的可用空间,这个时候会触发Full GC,如果老年代空间仍然不足,报 OutOfMemoryError
5、垃圾回收器
- 串行
- 单线程
- 适用于堆内存较小的机器,比如个人电脑
- 吞吐量优先
- 多线程
- 适用于堆内存较大,多核CPU的机器
- 让单位时间内,Stop the World的时间最短(例如一小时内:0.2 + 0.2 = 0.4s)
- 响应时间优先
- 多线程
- 适用于堆内存较大,多核CPU的机器
- 尽可能让单次 Stop the world 的时间最短(例如一小时内:0.1 + 0.1 + 0.1 + 0.1 + 0.1 = 0.5s)
| 名称 | 参数 | 备注 |
|---|---|---|
| 使用串行垃圾收集器 | -XX:+UseSerialGC | Serial(新生代-采用复制算法) + SerialOld(老年代-采用标记整理算法) |
| 使用吞吐量优先垃圾收集器:ParallelGC | -XX:+UseParallelGC -XX:+UseParallelOldGC | -XX:+UseParallelGC(新生代-采用复制算法) -XX:+UseParallelOldGC(老年代-采用标记整理算法),这两个收集器只要开启其中一个,另一个会自动启用 |
| 选项 | -XX:ParallelGCThreads=n | 指定该垃圾收集器工作时的垃圾收集线程数 |
| 开关 | -XX:+UseAdaptiveSizePolicy | 采用自适应的大小调整策略,允许该收集器动态调整新生代各区的比例,以及对象晋升老年代的年龄阈值 |
| 可选目标(二选一) | -XX:GCTimeRatio=ratio | 吞吐量目标,默认值为99,计算公式:1/(1+ratio),例如当ratio=99,则目标为0.01,表示单位时间内用于垃圾收集的时间不能超过运行时间的1%,运行100分钟则不能超过1分钟,如果超过这个值,该收集器会尝试调整堆的大小(一般会调大,通过减少GC次数来增大吞吐量),使之达到这个目标(实际情况中0.01的目标较难达到,参考值19即0.05) |
| 可选目标(二选一) | -XX:MaxGCPauseMillis=ms | 最大STW目标,默认值200ms |
| 使用响应时间优先的垃圾收集器 | -XX:+UseConcMarkSweepGC -XX:+UseParNewGC | -XX:+UseConcMarkSweepGC(老年代-采用标记清除算法),-XX:+UseParNewGC(新生代-采用复制算法),但是CMS有可能会并发失败(由于标记清除算法导致的内存碎片过多),当并发失败时,其退化为使用一次SerialOld(老年代-标记整理算法,单线程,串行)来收集垃圾,垃圾回收的时间将会飙升,随后重新使用CMS |
| 初始标记时受到这两个参数影响 | -XX:ParallelGCThreads=n -XX:ConcGCThreads=threads | n设置JVM的总线程数(用户线程+垃圾收集线程,参考值:机器CPU核数),threads设置垃圾收集线程数,参考值n/4 |
| 老年代GC的百分比条件:浮动垃圾 | -XX:CMSInitiatingOccupancyFraction=percent | percent默认值65,由于垃圾收集线程和用户线程并发执行,在真正清理垃圾时,用户线程会产生新的垃圾,称为浮动垃圾,所以垃圾收集线程不应该等到内存不足时才开始工作(否则浮动垃圾无法存放,违背了该垃圾收集器并发的主旨),必须为垃圾收集线程设置一个条件:当老年代内存占比超过percent时,垃圾收集线程就开始工作 |
| 开关 | -XX:+CMSScavengeBeforeRemark | 由于当CMS执行到重新标记时,由于新生代对象可能会引用老年代对象,需要对整个堆做一次可达性分析,但新生代的对象数量较多且生命周期短,可能等CMS工作完成后就死亡了,如此CMS便做了无用功,对性能影响较大,可以用此参数开启当CMS重新标记前对新生代执行一次GC,减轻重新标记时的压力(由ParNew垃圾收集器执行) |
吞吐量优先的垃圾收集器:Parallel
为并行收集,当它工作时,用户线程全部暂停,Parallel使用多个线程收集垃圾。

响应时间优先的垃圾收集器:ConcMarkSweep
简称CMS,为并发收集,当垃圾收集工作进行时,只有某些阶段需要STW,另外的阶段可以和用户线程并发执行
4、G1 垃圾收集器
- 适用场景:
- 同时注重吞吐量(Throughput)和低延迟(Low latency),默认的暂停目标是200ms
- 超大堆内存,会将堆划分为多个大小相等的Region,每个Region都可以独立的作为eden,survivor,old
- 整体上是标记+整理算法,两个区域(Region)之间是复制算法
- 相关JVM参数
| 名称 | 参数 | 备注 |
|---|---|---|
| 开关 | -XX:+UseG1GC | 使用G1作为垃圾收集器,G1在jdk9及其以后成为默认的垃圾收集器 |
| 调整Region的大小 | -XX:G1HeapRegionSize=size | G1垃圾收集器将堆内存划分为多个大小相等的Region,此参数用于调整每个Region的大小 |
| 最大暂停时间 | -XX:MaxGCPauseMillis=time |
第一阶段:新生代垃圾回收

第二阶段:新生代垃圾回收+并发标记
- 在Young GC时会进行GC Root的初始标记
- 老年代占用堆空间比例达到阈值时,进行并发标记(不会STW),由此参数决定:
-XX:initiatingHeapOccupancyPercent=percent(默认值45:当所有老年代Region占用到整个堆空间45%时)
![]()
第三阶段:混合收集 - 会对eden,survivor,old区进行全面的垃圾回收
- 最终标记(Remark)会STW:在第二阶段混合标记时,可能会漏掉一些对象,必须进行最终标记
- 拷贝存活(Evacuation)会STW
- 相关参数:
-XX:MaxGCPauseMillis=ms,针对老年代回收时间可能会过长的问题,收集器会根据这个参数挑选一些回收价值较高的Region进行存活对象拷贝
![]()



浙公网安备 33010602011771号