在学习java的jvm内存板块时,最后总会涉及到一些JVM参数。年轻代、老年代、永久代等各项都可以通过JVM参数来设置大小。在实际设置启动参数时,一般只会设置几个,实际参数有上百个,很多都有默认值。
JVM中,上一个版本的默认值并不一定是下一版本的默认值,不同的GC方式有不同的整套默认值,os不同,jvm位数不同,默认值都会有所区别。jdk1.6 高版本的update中参数得有600个。参数过多,不需要全部了解,只要知道的是找到默认值的方法,掌握默认值的大概量级、在不同的版本下哪些是常用的默认参数,哪些是必须设置的参数,哪些是可以选择的,哪些是尽量不要碰的。
看默认值的方法?
1、通过jinfo来获取。比如,jinfo -flag -PrintHeapAtGC=true <pid>
2、通过java -XX:+PrintFlagsFinal -version来获取结果。
3、通过java -XX:+PrintCommandLineFlags来打印真正的参数启动命令。
4、如果这些参数还不够全,可以打开几个开关:
java -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal -version
大部分的参数都可以安全的看到默认值,但是某些参数需要在生产环境运行时来调整。(后面花括号里面有product的表示可以在启动参数中设置的,花括号里面是“product rw”的表示还可以在jvm启动后使用类似下面的命令来设置这些参数)
项多时,可以根据grep命令指定单一项参数。
$ java -XX:+PrintCommandLineFlags -version-XX:InitialHeapSize=128163136 -XX:MaxHeapSize=2050610176 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC java version "1.8.0_144"Java(TM) SE Runtime Environment (build 1.8.0_144-b01)Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)
JVM参数设置中,有的是同一类型有很多参数,而且都有默认值。如-XX:NewSize、-XX:MaxNewSize,设置了xmn后相当于将这两值值设置为一样大。也有用参数-XX:NewRatio来设置的。不要混用,否则实际就并不知如何执行的。
参数 -XX:+PrintTenuringDistribution 输出中的部分值可以通过其它参数控制。
通过 -XX:InitialTenuringThreshold 和 -XX:MaxTenuringThreshold 可以设定老年代阀值的初始值和最大值。
通过参数 -XX:TargetSurvivorRatio 设定幸存区的目标使用率.例如 , -XX:MaxTenuringThreshold=10 -XX:TargetSurvivorRatio=90 设定老年代阀值的上限为10,幸存区空间目标使用率为90%。
新生代的GC 使用复制算法。
进入老年代的可能:1)复制对象超过gc次数;2)复制对象大于from/to区大小;3)创建对象大于新生代剩余空间大小;
如果新生代过小,会导致新生对象很快就晋升到老年代中,在老年代中对象很难被回收。有多种方式,设置新生代行为,没有通用准则。我们必须清楚以下2中情况:
1 如果从年龄分布中发现,有很多对象的年龄持续增长,在到达老年代阀值之前。这表示 -XX:MaxTenuringThreshold 设置过大2 如果 -XX:MaxTenuringThreshold 的值大于1,但是很多对象年龄从未大于1.应该看下幸存区的目标使用率。如果幸存区使用率从未到达,这表示对象都被GC回收,这正是我们想要的。 如果幸存区使用率经常达到,有些年龄超过1的对象被移动到老年代中。这种情况,可以尝试调整幸存区大小或目标使用率。
Application time: 0.3440086 secondsTotal time for which application threads were stopped: 0.0620105 secondsApplication time: 0.2100691 secondsTotal time for which application threads were stopped: 0.0890223 seconds
从中可以得知应用程序在前344毫秒中是在处理实际工作的,然后将所有线程暂停了62毫秒,紧接着又工作了210ms,然后又暂停了89ms。
-XX:+PrintGCDetails -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime输出则变成这样了;
[Full GC (Ergonomics) [PSYoungGen: 1375253K->0K(1387008K)] [ParOldGen: 2796146K->2049K(1784832K)] 4171400K->2049K(3171840K), [Metaspace: 3134K->3134K(1056768K)], 0.0571841 secs] [Times: user=0.02 sys=0.04, real=0.06 secs]Total time for which application threads were stopped: 0.0572646 seconds, Stopping threads took: 0.0000088 seconds
综上可知,应用线程被强制暂停了57ms来进行垃圾回收。其中又有0.008ms是用来等待所有的应用线程都到达安全点。
详细了解安全点信息:-XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1 会使得JVM会将一些额外的信息记录到标准输出中
参数 -XX:+PrintTenuringDistribution 指定JVM 在每次新生代GC时,输出幸存区中对象的年龄分布。
[GC [DefNew: 1986K->128K(2112K),0.0011191 secs] 27809K->27808K(30528K), 0.0011425 secs] [Times: user=0.00sys=0.01, real=0.00 secs]
[GC [ParNew: 1990K->132K(2112K),0.0007742 secs] 24112K->24110K(30528K), 0.0007964 secs] [Times: user=0.00sys=0.00, real=0.00 secs]
[GC [PSYoungGen:7449K->3728K(7552K)] 66980K->66980K(75136K), 0.0022792 secs] [Times:user=0.00 sys=0.00, real=0.00 secs]
GC[ParNew 表示使用的是parNew收集器。
GC[DefNew 表示用的是serial收集器。
[GC[PSYoungGen 表示用的是Parallel Scavenge收集器。