JVM/GC
已更新完—有需要补充的请留言,大家一起学习
JVM(java虚拟机)
参数类型 | 实例 | 解释说明 |
---|
标准参数 | -help | 很稳定,占时的JVM版本中都不会进行改变 |
-X参数(非标准参数) | -Xint | 不稳定,在未来的一些版本中可能会进行一些改变 |
-XX参数(使用率较高) | -XX:UseSerialGC | 再JVM的调优或者JVM的debugger中使用 |
情况\参数 | -server | -clinet |
---|
初始堆空间 | 大一些 | 小一些 |
默认回收器 | 并行垃圾回收器 | 串行垃圾回收器 |
启动速度 | 慢 | 快 |
运行速度 | 快 | 慢 |
32位操作系统(window) | - | 默认 |
32位操作系统(其他)2GB以上的内存,2个以上的CPU | 默认 | 否则选择该模式 |
64位操作系统 | 是 | 不支持 |
mkdir /test
cd /test/
ll
vim TestJVM.java
public static void main(String[] args) {
String str = System.getProperty("str");
if (str == null) {
System.out.println("this str =null");
} else {
System.out.println(str);
}
}
javac TestJVM.java
java TestJVM
java -Dstr=hello TestJVM

java -client -showversion TestJVM
java -server-showversion TestJVM
java -X
-X参数 | 作用 | 解释说明 |
---|
-Xmixed | 混合模式执行 (默认) | 价格解释模式和编译迷失进行混合使用,由JVM自己决定,这是jvm的默认模式也是推荐模式 |
-Xint | 仅解释模式执行 | 标记会强制JVM执行所有的字节代码,这样就会降低了运行速度,通常是低10倍以上 |
-Xcomp | 编译模式 | 和Xint相反,jvm再第一次使用的时候会把所有的字节码编译到本地代码,从而大大的速度上的优化,但是很多应用在使用这个模式的时候都会有一些性能的损失.但是比使用-Xint损失少点,原因是他没有让JIT启动it编译器的全部功能,JIT编译器可以Udine是否需要编译做出判断,如果所有的代码都进行了编译,对于一些只执行一次代码就没有意义了 |
-Xbootclasspath | <用 ; 分隔的目录和 zip/jar 文件>设置搜索路径以引导类和资源 | – |
-Xbootclasspath/a | <用 ; 分隔的目录和 zip/jar 文件> 附加在引导类路径末尾 | – |
-Xbootclasspath/p | <用 ; 分隔的目录和 zip/jar 文件>置于引导类路径之前 | – |
-Xdiag | 显示附加诊断消息 | – |
-Xnoclassgc | 禁用类垃圾收集 | – |
-Xincgc | 启用增量垃圾收集 | – |
-Xloggc:< file > | 将 GC 状态记录在文件中 (带时间戳) | – |
-Xbatch | 禁用后台编译 | – |
-Xms< size > | 设置初始 Java 堆大小 | – |
-Xmx< size > | 设置最大 Java 堆大小 | – |
-Xss< size > | 设置 Java 线程堆栈大小 | – |
-Xprof | 输出 cpu 配置文件数据 | – |
-Xfuture | 启用最严格的检查, 预期将来的默认值 | – |
-Xrs | 减少 Java/VM 对操作系统信号的使用 (请参阅文档) | – |
-Xcheck:jni | 对 JNI 函数执行其他检查 | – |
-Xshare:off | 不尝试使用共享类数据 | – |
-Xshare:auto | 在可能的情况下使用共享类数据 (默认) | – |
-Xshare:on | 要求使用共享类数据, 否则将失败。 | – |
-XshowSettings | 显示所有设置并继续 | – |
-XshowSettings:all | 显示所有设置并继续 | – |
-XshowSettings:vm | 显示所有与 vm 相关的设置并继续 | – |
-XshowSettings:properties | 显示所有属性设置并继续 | – |
-XshowSettings:locale | 显示所有与区域设置相关的设置并继续 | – |
-XX参数
类型 | 格式 | 实例 |
---|
boolean类型 | -XX:[+ -]< name >表示启用或者禁用< name >属性 | -XX:DisableExplicitGC表示禁用手动调用GC操作,也就是说System.gc()无效 |
非boolean类型 | -XX:< name > =< value >表示< name >属性值为< value > | -XX:NewRatio = 1表示新生代和老年代的比值 |
下面的属于-XX的参数范围
参数 | 解释说明 |
---|
-Xms | 设置JVM的堆内存初始大小 |
-Xmx | 设置JVM的堆内存最大大小 |
java -Xms512m -Xmx2048m TestJVM来
什么时候需要查看JVM的运行参数
jvm的内存模型
1.7版本

1.8版本


可以看出1.8版本的组成为:年轻代 + 老年代
年轻代: Eden + 2个Survivor
老年代:OldGen
元数据空间:所占用的内存空间不是再虚拟机内部的,而是再本地内存空间中
通过jstat命令进行查看堆内存的使用情况
参数 | 解释说明 |
---|
Loaded | 加载class的数量 |
Bytes | 所占用的空间大小 |
Unloaded | 未加载数量 |
Bytes | 未加载占用的空间 |
Time | 总时间 |
参数 | 解释说明 |
---|
Compiled | 编译的数量 |
Failed | 失败数量 |
Invalid | 不可用数量 |
Time | 总时间 |
FailedType | 失败类型 |
FailedMethod | 失败的方法 |
参数 | 解释说明 |
---|
S0C | 第一个Survivor区的大小 |
S1C | 第二个Survivor区的大小 |
S0U | 第一个Survivor区的使用大小 |
S1U | 第二个Survivor区的使用大小 |
EU | Eden区的大小 |
EC | Eden区的使用大小 |
OC | Old区的大小 |
OU | Old区的使用大小 |
MC | 方法区大小 |
MU | 方法区使用大小 |
CCSC | 压缩类空间大小 |
CCSU | 压缩类空间使用大小 |
YGC | 年轻代垃圾回收次数 |
YGCT | 年轻代垃圾回收耗时时间 |
FGC | 老年代垃圾回收次数 |
FGCT | 老年代垃圾回收耗时时间 |
GCT | 垃圾回收耗时总时长 |
对象 | 说明 |
---|
B | BYTE |
C | CHAR |
D | DOUBLE |
F | FLOAT |
I | INT |
J | LONG |
Z | BOOLEAN |
[ | 数组例如:[I表示的就是int[] |
[L+类名 | 其他对象 |
MAT
打开文件

选择之前的dump的文件



jstack(将正在运行的JVM的线程进行快照并且打印出来)
状态 | 解释说明 |
---|
初始状态(NEW) | 创建一个Thread对象,但是还没有调用start()启动线程时,线程处于初始状态 |
运行状态(Runnable) | 再java中,运行状态包括就绪状态和运行状态 |
运行状态(就绪状态) | 这个状态下的线程已经获取到了所要执行的资源,只需要分配CPU执行权即可执行,所有的就绪状态的线程都是存放在就绪队列中的 |
运行状态(运行状态) | 获取到CPU的执行权,正在执行线程,由于一个cpu同一时刻只能执行一个线程,所以每一个cpu每个时刻只有一条运行状态的线程 |
阻塞状态(Blocked) | 当每一个正在执行的线程请求某一条资源失败的时候就会进入阻塞状态,在java中阻塞状态专指请求锁失败时进入的状态,由于一个阻塞队列存放所有的阻塞状态的线程,处于阻塞状态的线程会不断的请求资源,一旦请求成功,就会进入就绪状态等待执行 |
等待状态(Waiting) | 当前线程中调用wait,join,park函数的时候,当前线程就会进入等待状态,也有一个等待的队列存放在所有的等待状态的线程;线程处于等待状态表示需要等待其他的线程的指示才能继续运行;进入等待状态的线程会释放CPU的执行权,并且释放资源(如:锁) |
超时等待状态(Timed_Waiting) | -当运行的线程调用sleep(time),wait,join,parkNanos,parkUntil的时候,就会进入到这个状态; 他和等待状态一样,并不是因为请求不到资源,而是主动的进入,并且进入后需要其他线程的唤醒;进入这个状态后释放CPU执行权和占有的资源; 与等待状态的区别就是,到了超时时间以后自动进入阻塞队列,开始竞争锁 |
终止状态(Terminated) | 线程执行结束后的状态 |
死锁
VisualVM工具(监控线程内存使用情况)

VisualVM命令
- 内存信息
- 线程信息
- Dump堆(本地进程)
- Dump线程(本地进程)
- 打开对Dump,堆Dump可以用jmap来生成
- 打开线程Dump
- 生成应用快照(包含内存信息,线程信息等等)
- 性能分析,CPU分析(各个方法调用时间,检查那些方法耗时长),内存分析(各类对象占用的内存,检查那些类占用的内存多)





监控远程的JVM
JMX


分析堆日志
"Thread-1" #12 prio=5 os_prio=0 tid=0x00007f8e04001800 nid=0x5103 waiting on condition [0x000070000e2ef000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.example.MyApp.processData(MyApp.java:45)
at com.example.MyApp.run(MyApp.java:23)
at java.lang.Thread.run(Thread.java:748)
"Thread-2" #13 prio=5 os_prio=0 tid=0x00007f8e04002000 nid=0x5203 waiting on condition [0x000070000e3f2000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.example.MyApp.processData(MyApp.java:45)
at com.example.MyApp.run(MyApp.java:23)
at java.lang.Thread.run(Thread.java:748)
"Thread-3" #14 prio=5 os_prio=0 tid=0x00007f8e04002800 nid=0x5303 waiting on condition [0x000070000e4f5000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x000000076af8aeb8> (a java.util.concurrent.CountDownLatch$Sync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:
997)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231)
at com.example.MyApp.processData(MyApp.java:60)
at com.example.MyApp.run(MyApp.java:23)
at java.lang.Thread.run(Thread.java:748)
什么情况下可能需要JVM调优
- 堆内存持续增长:如果应用程序的堆内存持续增长并且接近或达到了最大内存限制(由 -Xmx 参数设置),这可能表明存在内存泄漏或者内存使用不合理的情况,需要进行调优来优化内存使用。
- 频繁的Full GC:如果应用程序中频繁发生Full GC,即对整个堆进行回收的情况,这可能会导致较长的停顿时间和性能下降。调优的目标是尽量减少Full GC的次数。
- 垃圾回收停顿时间过长:如果垃圾回收的停顿时间超过了可接受的范围(一般认为超过1秒),可能会影响应用程序的响应性能和用户体验。调优的目标是减小垃圾回收的停顿时间。
- 内存异常:如果应用程序经常遇到内存异常,如OutOfMemoryError,表明应用程序的内存使用超出了JVM的限制,需要调优来提高内存的利用率和稳定性。
- 大量占用内存的本地缓存:如果应用程序中使用了大量的本地缓存,并且占用了大量的内存空间,可能会导致内存不足的问题。调优的目标是优化缓存策略和内存管理,减少内存占用。
- 性能不佳或不稳定:如果应用程序的吞吐量和响应性能不高或不稳定,可能是由于内存管理不当导致的。调优的目标是提高应用程序的性能和稳定性。
- 除了命令行参数外,可以在应用程序代码使用System.setProperty()方法来动态设置JVM参数如:
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "8");
补充JVM内部结构

JVM 调优策略(补充)
GC
垃圾回收算法
1.引用计数法
循环引用
A a = new A();
B b = new B();
a.b=b;
b.a=a;
a=null;
b=null;
2.标记清除发
3.标记压缩算法
4.复制算法
5.分代算法
算法 | 优点 | 缺点 | 说明 |
---|
引用计数法 | 1.实用性较高,无需等到内存不够的时候,才可以进行回收,运行的时候根据对象的计数器是否为0,就可以直接进行回收了 2.在垃圾回收的过程中,引用无需挂起,如果申请内存的时候内存不足,则会立即outofmenber错误 3.区域性,更新对象的计数器的时候,只是影响到该对象,不会扫描全部的对象 | 1.对象每次被引用的时候,都需要去更新计数器,有一定时间的开销2.浪费cpu资源,即使是内存足够的情况下,任然运行时进行着计数器的统计 3.无法解决循环引用的问题(最大的缺点) | 假设有一个对象A,任何一个对象对A的引用,那么对象A的引用计数器+1,当引用失败的时候,对象A的引用计数器就-1,如果对象A的计数器值为0,就是说明A没有被引用,可以被回收了 |
标记清除算法 | 1.解决了循环引用的问题 | 1.效率比较低,标记和清除2个动作都是需要遍历所有的对象,并且再GC的时候需要暂停应用程序,对于交互性要求高的应用而言这个体验是非常差的 2.通过标记清除的算法清理出来的内存,碎片化比较严重,因为被回收的对象可能存在于内存的各个角落,所以清理出来内存是不连贯的 | 是将垃圾护手分为2个阶段,分别为标记和清除1.标记:从根节点开始标记引用的对象2.清除:未被标记引用的对象就是垃圾回收对象,可以被清理;暂停程序线程,没有被标记的对象会被回收清除掉然后被标记的对象留下来并进行重置变为未标记的状态,恢复程序线程,程序继续运行 |
标记压缩算法 | 解决了标记清除法里面而定碎片化问题 | 标记压缩算法多了一个压缩的步骤,这样就会导致其中的清除的整体效率受到了影响 | 再标记清除算法的基础之上做的优化,和标记清除算法一样,也是从根节点开始,对对象的应用进行标记,在清理的阶段,并不是简单地清理未标记的对象,而是将存货的对象压缩到哦内存的一段,然后清理边界意外的垃圾,从而解决碎片化的问题 |
复制算法 | 1.在垃圾对象多的情况下,效率高 2.清理以后,内存无碎片 | 1.再垃圾对象少的时候不适合 2.分配的2块内存空间,再同一时刻只能使用一半,内存使用率较低 | 将原有的内存空间一分为二,每次只用到其中的一块,在垃圾回收的时候,将正在使用的对象复制到另一个内存空间中,然后将该内存空间清空,交换内存的角色,完成垃圾回收 |
分代算法 | – | – | 分代算法指的是根据回收对象的特点进行选择,再jvm中,年轻代适合复制算法,老年代适合标记清除或者标记压缩算法 |
收集器
参数 | 说明 |
---|
-XX:UseSerialGC | 指定的年轻代和老年代都使用串行垃圾收集器 |
-XX:+PrintGCDetails | 打印垃圾回收的详细信息 |
-XX:UseParallelGC | 年轻代使用ParallelGC垃圾回收期,老年代使用串行回收器 |
-XX:UseParallelOldGC | 年轻代使用ParallelGC垃圾回收期,老年代使用ParallelOld垃圾回收器 |
-XX:MaxGCPauseMillis | (设置最大的垃圾收集时候的停顿时间,单位毫秒,需要注意的是ParallelGC为了达到设置的停顿时间,可能会调整堆的大小或者其他的参数,如果堆的大小设置的比较小,就会导致GC工作变得很频繁,反而可能会影响到性能,这个参数使用的时候需要谨慎处理) |
-XX:GCTimeRatio | (设置垃圾回收时间占程序运行时间的百分比,公式:1/(1+n),他的值为0~100之间的数字,默认值为99,也就是垃圾回收事假不能超过1%) |
-XX:UseAdaptiveSizePolicy | (自适应GC模式,垃圾回收器将会自动的调整新生代,老年代等参数,达到吞吐量,堆大小,停顿时间之间的平衡;一般用于手动的调整比较困难的场景,让收集器自动的进行调整) |
-XX:+UseG1GC | 使用G1垃圾收集器 |
-XX:+MaxGCPauseMillis | 设置期望达到的最大GC停顿时间指标,默认是200毫秒,但是jvm不一定能保证达到这个指标 |
-XX:+ParallelGCthreads=n | 设置STW工作线程数的值,将n的值设置为逻辑处理器的值.n的值与逻辑处理器的数量相同,最多为8 |
-XX:+ConcGCThreads=n | 设置并行标记的线程数,将n设置为并行垃圾回收线程数的1/4左右 |
-XX:+G1HeapRegionSize | 设置的G1区域的大小,值是2的幂,范围是1mb~32mb之间,目标是根据最小dejava堆大小划分为≈2048个区域, 默认是堆内存的1/2000 |
-XX:+InitiatingHeapOccupancyPercent=n | 设置处罚标记周期的java堆占用率阀值,默认占用率是整个java堆的45% |

参数 | 解读 | 冒号后面的内容解释 |
---|
DefNew | 表示使用的是串行垃圾收集器 | 4416K->512K(4928K)====>表示年轻代GC占用的内存是4416K内存,GC之后占用512K内存总大小4928K;0.0046102 secs =====>表示的是GC所用的时间单位毫秒 ; |
-XX:+PrintGCDetails | 打印垃圾回收的详细信息 | – |
1.串行垃圾收集器
-XX:+UseSerialGC -XX:+PrintGCDetails -Xms16m -Xmx16m
2.并行垃圾收集器

2.CMS垃圾收集器
3.G1垃圾收集器(重点)jdk1.7开始1.9默认的回收器
Young GC模式

Mixed GC
可视化的GC日志分析工具