常见参数
java启动参数
参数 | 说明 |
---|---|
- | 所有jvm实现都必须实现这些参数的功能,向后兼容 |
-X | 默认jvm实现这些参数的功能,不保证所有jvm实现都满足,不保证向后兼容 |
-XX | 各个jvm实现有所不同,可能会随时取消 |
输出jvm的信息参数
参数 | 说明 |
---|---|
-verbose:gc | 输出每次GC的相关信息 |
-XX:+PrintGCDetails | 获取的信息比上面更多 |
更多信息
参数 | 说明 |
---|---|
-XX:PrintGCTimeStamps | 显示jvm启动到执行GC时流逝的时间,单位是秒 |
-XX:PrintDateTimeStamps | 显示执行GC时的本地时间(Java 6 update 4才开始支持) |
-Xloggc:/Users/cc/Desktop/log.txt | gc信息重定向到文件 |
解读log信息
CommandLine flags: -XX:InitialHeapSize=134217728 -XX:MaxHeapSize=2147483648 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
0.465: [GC (System.gc()) [PSYoungGen: 5341K->851K(38400K)] 5341K->859K(125952K), 0.0020406 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
0.467: [Full GC (System.gc()) [PSYoungGen: 851K->0K(38400K)] [ParOldGen: 8K->778K(87552K)] 859K->778K(125952K), [Metaspace: 3653K->3653K(1056768K)], 0.0064182 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
Heap
PSYoungGen total 38400K, used 1553K [0x0000000795580000, 0x0000000798000000, 0x00000007c0000000)
eden space 33280K, 4% used [0x0000000795580000,0x00000007957045f8,0x0000000797600000)
from space 5120K, 0% used [0x0000000797600000,0x0000000797600000,0x0000000797b00000)
to space 5120K, 0% used [0x0000000797b00000,0x0000000797b00000,0x0000000798000000)
ParOldGen total 87552K, used 778K [0x0000000740000000, 0x0000000745580000, 0x0000000795580000)
object space 87552K, 0% used [0x0000000740000000,0x00000007400c2ab8,0x0000000745580000)
Metaspace used 3775K, capacity 4888K, committed 5120K, reserved 1056768K
class space used 419K, capacity 456K, committed 512K, reserved 1048576K
System.out.println(Runtime.getRuntime().maxMemory()); System.out.println(Runtime.getRuntime().freeMemory()); System.out.println(Runtime.getRuntime().totalMemory());
JVM内存结构
JVM的内存由栈寄存器和堆构成,堆里面有新生代、老年代和持久代。
Young(年轻代)
分为Eden(伊甸)区,两个survivor(存活)区。大部分对象(刚new出的对象)在Eden区,当Eden区满时,还存货的对象被复制到survivor区中的一个,当这个survivor区满时,此区的存活对象将被复制到另外一个survivor区,当这个survivor区满时,从第一个survivor区复制过来的并且此时还存活的对象,被复制到“老年代”。survivor总有一个是空的。
Tenured(老年代)
老年代存放从年轻代存活的对象,一般来说老年代存放的都是生命周期较长的对象
Perm(持久代)
用于存放静态文件,如java类,方法。持久代对垃圾回收没有显著影响.final修饰的常量,classLoader加载的信息。
GC的两种类型
ScavengeGC(Minor GC) | Full GC |
---|---|
一般情况下,当新对象生成并且在Eden申请空间失败时,触发scavengeGC,堆Eden区域进行GC,清楚非存活对象,并将尚且存活的对象移动到survivor区,然后整理survivor的两个区 | 对整个堆进行真理,包括young tenured和perm。 |
触发:Eden区满 | 触发full gc的三种原因:tenured被写满;perm被写满;System.gc()被显式调用 |
新生代发生的垃圾回收操作,因为java对象大多具有朝生夕灭的特性,所以minorGC非常频繁,一般回收速度也比较快,通常在百毫秒级 | 老年代GC(FullGC/MajorGC)发生在老年代的GC,出现了MajorGC经常会伴随至少一次的MinorGC(非绝对,在parallelscavenge收集器的手机策略里就有直接进行majorGC的策略选择过程)。majorGC的速度一般会比MinorGC慢10倍以上,1.4G的Old Gen进行一次回收通常需要20-40秒 |
首次YGC:对Eden区进行垃圾回收,回收后Eden区中依然存活的对象被移入S0 第二次YGC:将s0中的对象复制到s1,并对Eden区和s1进行垃圾回收,回收后Eden区依然存活的对象被移入s1,并将s0中所有的对象清楚,以此类推,在S0/S1中存活次数超过N次(默认15次)的对象移入OldGen,如果S0/S1空间不足,则直接移入Old Gen | 对young gen,old gen,perm gen进行一次完整的垃圾回收,old gen不在被引用的对象直接销毁,young gen的回收算法同youngGC,perm GEM回收方式为,如果堆中不存在某个类的任何势力,且该类的Class对象没有在任何地方被引用,则该类被回收 |
虚拟机给每个对象定义了一个对象年龄(Age)计数器,如果对象在Eden出生并经过第一次MinorGC后仍然存活,并且能被survivor容纳的话,将被移动到survivor空间中,并将对象年龄设为1.对象在survivor区中每熬过一次MinorGC,年龄就增加一岁,当它的年龄增加到一定程度(默认为15岁)时,就会被晋升到老年代中。对象晋升老年代的年龄阈值 通过-XX:MaxTenuringThreshhold来设置
jstat -gcutil <pid> <timediff>
用jstat查看jvm内存使用情况
s0 | s1 | E | O | P | YGC | YGCT | FGC | FGCT | GCT |
---|---|---|---|---|---|---|---|---|---|
S0区占用的空间比 | s1 | Eden区 | Old区 | Perm区 | YGC的次数 | YGCtime从程序启动到采用ygc所有的时间/s | FGC次数 | FGC时间/s | 用于垃圾回收的总时间/s |
xiejiangqiongdeMacBook-Pro:~ cc$ jstat -gcutil 5061 1000
Warning: Unresolved Symbol: sun.gc.generation.2.space.0.capacity substituted NaN
Warning: Unresolved Symbol: sun.gc.generation.2.space.0.used substituted NaN
Warning: Unresolved Symbol: sun.gc.generation.2.space.0.capacity substituted NaN
S0 S1 E O P YGC YGCT FGC FGCT GCT
75.66 0.00 0.00 99.76 � 18 2.212 5 2.398 4.610
73.66 0.00 20.00 65.58 � 18 2.212 5 4.433 6.645
73.66 0.00 44.00 65.58 � 18 2.212 5 4.433 6.645
73.66 0.00 64.00 65.58 � 18 2.212 5 4.433 6.645
73.66 0.00 84.00 65.58 � 18 2.212 5 4.433 6.645
73.66 0.00 100.00 65.58 � 18 2.212 5 4.433 6.645
0.00 100.00 8.00 68.23 � 19 2.613 5 4.433 7.046
0.00 100.00 32.00 68.23 � 19 2.613 5 4.433 7.046
0.00 100.00 50.00 68.23 � 19 2.613 5 4.433 7.046
0.00 100.00 68.00 68.23 � 19 2.613 5 4.433 7.046
0.00 100.00 86.00 68.23 � 19 2.613 5 4.433 7.046
2.72 100.00 100.00 81.55 � 20 2.613 5 4.433 7.046
51.81 0.00 0.00 88.70 � 20 3.010 6 4.433 7.443
5.87 0.00 2.00 69.16 � 20 3.010 6 6.121 9.130
5.87 0.00 30.00 69.16 � 20 3.010 6 6.121 9.130
5.87 0.00 54.00 69.16 � 20 3.010 6 6.121 9.130
用ps -ef | grep java
查看待检测进程的id
uid | pid | ppid | c | stime | tty | cmd |
---|---|---|---|---|---|---|
用户ID | 进程ID | 父进程ID | 开始时间 | 登录方式 | 命令 |
从我的毕设中大量的FullGC看内存
内存泄露时会发生什么
- 某些对象会占用大量的JVM内存,且长时间无法被回收掉。这些长时间无法被回收的对象通常都会在Old Gen中
- 由于Old Gen中存在大量无法被回收的对象,每次FullGC只能释放出极少的Old Gen空间,回收处的这少部分Old Gen空间又会很快被占满,这就会导致JVM在频繁地进行FullGC
- FullGC很慢,而JVM在做GC时会stop-the-world,在GC时终止JVM的一切工作。所以假设在内存泄露发生时,JVM被迫每40秒做一次FullFC,每次FullGC需要30秒,这就代表JVM只有1/4的时间在正常工作,此时的性能一定是非常慢的
- 而随着泄露对象的不断增加,OldGen的可用空间会越来越少,最终JVM会回收不出足够的可用内容以支撑程序的运行,从而导致服务的彻底不可用
通过jstat观察Old Gen内存占用的增长速度,以及GC的频次
- 如果jstat命令输出的信息表示JVM正在频繁进行FullGC,那么基本而已肯定性能故障的原因是内存泄露
[Full GC (Ergonomics) 3344336K->3068858K(3749376K), 3.7187515 secs]
[Full GC (Ergonomics) 3344336K->3091406K(3749376K), 3.2715931 secs]
[Full GC (Ergonomics) 3344336K->3112195K(3749376K), 3.9227456 secs]
[Full GC (Ergonomics) 3344336K->3139728K(3749376K), 3.5998555 secs]
参考博客
日志信息解读
IDEA JVM运行参数
JVM参数原理和性能调优
jvm调优总结+jstat分析 很好的总结
java gc的工作原理 minor gc full gc的原理
关于tomcat上的性能