jvm

Posted XiaoMaPro

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jvm相关的知识,希望对你有一定的参考价值。

1、JVM空间说明

  • JDK 1.7及以前,java类的信息、常量池、静态变量都存在Permanent中,类的元数据和静态变量在类加载的时候分配到permanent中,只有当类被销毁的时候垃圾收集GC会从permanent中处理掉
  • JDK 1.8 的对 JVM 架构的改造将类元数据放到本地内存中,将常量池和静态变量放到 Java 堆里。HotSoptVM 将会为类的元数据明确分配和释放本地内存。在这种架构下,类元信息就突破了原来 -XX:MaxPermSize 的限制,所以PermSize的配置也是无效的,现在可以使用更多的本地内存。这样就从一定程度上解决了原来在运行时生成大量类的造成经常 Full GC 问题,如运行时使用反射、代理等.
  • 可以发现最明显的一个变化是元空间从虚拟机转移到本地内存;默认情况下,元空间的大小仅受本地内存的限制。这意味着以后不会因为永久代空间不够而抛出OOM异常了。jdk1.8以前版本的class和jar包数据存储在permGen下面 ,permGen大小是固定的,而且项目之间无法共用公有的class,所以很容易碰到OOM异常。
    改成metaSpaces后,各个项目会共享同样的class内存空间,比如多个项目都引用了common包,在metaSpaces中只会存储common的class,提高了内存的利用率,垃圾回收更有效率。

2、JVM参数配置

1.在jdk1.8以前,生产环境一般有如下配置

-XX:PermSize=512M -XX:MaxPermSize=1024M

表示在JVM里存储Java类信息,常量池和静态变量的永久代区域初始大小为512M,最大为1024M。在项目启动后,这个值是固定的,如果项目class过多,很可能遇到OutOfMemoryError: PermGen异常。
2.升级JDK1.8之后,上面的perm配置已经变成

-XX:MetaspaceSize=512M XX:MaxMetaspaceSize=1024M

MetaspaceSize如果不做配置,通过jinfo查看默认MetaspaceSize大小(约21M),MaxMetaspaceSize很大很大,前面说过MetaSpace只受本地内存大小限制。MetaspaceSize为出发FullGC的阈值,默认约为21M,如做了配置,最小阈值为自定义配置大小。空间使用达到阈值,触发FullGC,同时对该值扩大。当然如果元空间实际使用小于阈值,在GC的时候也会对该值缩小。MaxMetaspaceSize为元空间的最大值,如果设置太小,可能会导致频繁FullGC,甚至OOM。

3、GarbageCollection过程

1、新new的对象都放在Eden区
2、Eden区满或者快满的时候进行一次清理(MinorGc),不被引用的对象直接被清理掉;还有引用的对象,但是年龄比较大的,挪到S0区
3、下次Eden区快满的时候,会进行上一步的操作,并且将Eden和S0区的年纪大的对象放到S1区,原理上随时保持S0和S1有一个是空的,用来存下一次的对象
4、下下次,Eden区快满的时候,会进行上一步操作,并且将Eden和S1区的年纪大的对象放到S0区,此时S1区就是空的
5、直到Eden区快满,S0或者S1也快满的时候,这时候就把这两个区的年纪大的对象放到Old区
6、依次循环,直到Old区也快满的时候,Eden区也快满的时候,会对整个这一块内存区域进行一次大清洗(FullGC),腾出内存,为之后的对象创建,程序运行腾地方。

清理Eden区和Survivor区叫Minor GC;清理Old区叫Major GC;清理整个堆空间—包括年轻代和老年代叫Full GC。

4、jvm建议配置

-XX:MetaspaceSize=128M -XX:MaxMetaspaceSize=256M -Xms256m -Xmx256m
设置元空间的初始值和最大值,设置堆空间的初始值和最大值。

MetaspaceSize要设置为128M?堆内存初始值Xms设置为256M而不是512M?
根据jdk官网的建议

Java堆大小设置,Xms 和 Xmx设置为老年代存活对象的3-4倍,即FullGC之后的老年代内存占用的3-4倍
永久代 PermSize和MaxPermSize(元空间)设置为老年代存活对象的1.2-1.5倍。(1.8以后彻底抛弃了)
年轻代Xmn的设置为老年代存活对象的1-1.5倍。
老年代的内存大小设置为老年代存活对象的2-3倍
类加载统计:
jstat -class pid(进程号)

Loaded | Bytes | Unloaded | Bytes | Time

LoadedBytesUnloadedBytesTime
加载class的数量所占用空间大小未加载数量未加载占用空间时间
编译统计
jstat -compiler pid(进程号)
CompiledFailedInvalidTimeFailedTypeFailedMethod
编译数量Failed:失败数量Invalid:不可用数量Time:时间FailedType:失败类型FailedMethod:失败的方法
垃圾回收统计
jstat -gc pid(进程号)
S0CS1CS0US1UECEUOCOUMCMUCCSCCCSUYGCYGCTFGCFGCTGCT
第一个幸存区的大小第二个幸存区的大小第一个幸存区的使用大小第二个幸存区的使用大小伊甸园区的大小伊甸园区的使用大小老年代大小老年代使用大小方法区大小方法区使用大小压缩类空间大小压缩类空间使用大小年轻代垃圾回收次数年轻代垃圾回收消耗时间老年代垃圾回收次数老年代垃圾回收消耗时间垃圾回收消耗总时间
堆内存统计
jstat -gccapacity pid(进程号)
NGCMNNGCMXNGCS0CS1CECOGCMNOGCMXOGCOCMCMNMCMXMCCCSMNCCSMXCCSCYGCFGC
新生代最小容量新生代最大容量当前新生代容量第一个幸存区大小第二个幸存区的大小伊甸园区的大小老年代最小容量老年代最大容量当前老年代大小当前老年代大小最小元数据容量最大元数据容量当前元数据空间大小最小压缩类空间大小最大压缩类空间大小当前压缩类空间大小年轻代gc次数老年代GC次数
新生代垃圾回收统计
jstat -gcnew pid(进程号)
S0CS1CS0US1UTTMTTDSSECEUYGCYGCT
第一个幸存区大小第二个幸存区的大小第一个幸存区的使用大小第二个幸存区的使用大小对象在新生代存活的次数对象在新生代存活的最大次数期望的幸存区大小伊甸园区的大小伊甸园区的使用大小年轻代垃圾回收次数年轻代垃圾回收消耗时间
新生代内存统计
jstat -gcnewcapacity pid(进程号)
NGCMNNGCMXNGCS0CMXS0CS1CMXS1CECMXECYGCFGC
新生代最小容量新生代最大容量当前新生代容量最大幸存1区大小当前幸存1区大小最大幸存2区大小当前幸存2区大小最大伊甸园区大小当前伊甸园区大小年轻代垃圾回收次数老年代回收次数
老年代垃圾回收统计
jstat -gcold pid(进程号)
MCMUCCSCCCSUOCOUYGCFGCFGCTGCT
方法区大小方法区使用大小压缩类空间大小压缩类空间使用大小老年代大小老年代使用大小年轻代垃圾回收次数老年代垃圾回收次数老年代垃圾回收消耗时间垃圾回收消耗总时间
老年代内存统计
jstat -gcoldcapacity pid(进程号)
OGCMNOGCMXOGCOCYGCFGCFGCTGCT
老年代最小容量老年代最大容量当前老年代大小老年代大小年轻代垃圾回收次数老年代垃圾回收次数老年代垃圾回收消耗时间垃圾回收消耗总时间
元数据空间统计
jstat -gcmetacapacity pid(进程号)
MCMNMCMXMCCCSMNCCSMXCCSCYGCFGCFGCTGCT
最小元数据容量最大元数据容量最大元数据容量最小压缩类空间大小最大压缩类空间大小最大压缩类空间大小年轻代垃圾回收次数老年代垃圾回收次数老年代垃圾回收消耗时间垃圾回收消耗总时间
总结垃圾回收统计
jstat -gcutil pid(进程号) 
S0S1EOMCCSYGCFGCFGCTGCT
幸存1区当前使用比例幸存2区当前使用比例伊甸园区使用比例老年代使用比例元数据区使用比例压缩使用比例年轻代垃圾回收次数老年代垃圾回收次数老年代垃圾回收消耗时间垃圾回收消耗总时间
JVM编译方法统计
jstat -printcompilation pid(进程号)
CompiledSizeTypeMethod
最近编译方法的数量最近编译方法的字节码数量最近编译方法的编译类型方法名标识

1、JVM空间说明

  • JDK 1.7及以前,java类的信息、常量池、静态变量都存在Permanent中,类的元数据和静态变量在类加载的时候分配到permanent中,只有当类被销毁的时候垃圾收集GC会从permanent中处理掉
  • JDK 1.8 的对 JVM 架构的改造将类元数据放到本地内存中,将常量池和静态变量放到 Java 堆里。HotSoptVM 将会为类的元数据明确分配和释放本地内存。在这种架构下,类元信息就突破了原来 -XX:MaxPermSize 的限制,所以PermSize的配置也是无效的,现在可以使用更多的本地内存。这样就从一定程度上解决了原来在运行时生成大量类的造成经常 Full GC 问题,如运行时使用反射、代理等.
  • 可以发现最明显的一个变化是元空间从虚拟机转移到本地内存;默认情况下,元空间的大小仅受本地内存的限制。这意味着以后不会因为永久代空间不够而抛出OOM异常了。jdk1.8以前版本的class和jar包数据存储在permGen下面 ,permGen大小是固定的,而且项目之间无法共用公有的class,所以很容易碰到OOM异常。
    改成metaSpaces后,各个项目会共享同样的class内存空间,比如多个项目都引用了common包,在metaSpaces中只会存储common的class,提高了内存的利用率,垃圾回收更有效率。

2、JVM参数配置

1.在jdk1.8以前,生产环境一般有如下配置

-XX:PermSize=512M -XX:MaxPermSize=1024M

表示在JVM里存储Java类信息,常量池和静态变量的永久代区域初始大小为512M,最大为1024M。在项目启动后,这个值是固定的,如果项目class过多,很可能遇到OutOfMemoryError: PermGen异常。
2.升级JDK1.8之后,上面的perm配置已经变成

-XX:MetaspaceSize=512M XX:MaxMetaspaceSize=1024M

MetaspaceSize如果不做配置,通过jinfo查看默认MetaspaceSize大小(约21M),MaxMetaspaceSize很大很大,前面说过MetaSpace只受本地内存大小限制。MetaspaceSize为出发FullGC的阈值,默认约为21M,如做了配置,最小阈值为自定义配置大小。空间使用达到阈值,触发FullGC,同时对该值扩大。当然如果元空间实际使用小于阈值,在GC的时候也会对该值缩小。MaxMetaspaceSize为元空间的最大值,如果设置太小,可能会导致频繁FullGC,甚至OOM。

3、GarbageCollection过程

1、新new的对象都放在Eden区
2、Eden区满或者快满的时候进行一次清理(MinorGc),不被引用的对象直接被清理掉;还有引用的对象,但是年龄比较大的,挪到S0区
3、下次Eden区快满的时候,会进行上一步的操作,并且将Eden和S0区的年纪大的对象放到S1区,原理上随时保持S0和S1有一个是空的,用来存下一次的对象
4、下下次,Eden区快满的时候,会进行上一步操作,并且将Eden和S1区的年纪大的对象放到S0区,此时S1区就是空的
5、直到Eden区快满,S0或者S1也快满的时候,这时候就把这两个区的年纪大的对象放到Old区
6、依次循环,直到Old区也快满的时候,Eden区也快满的时候,会对整个这一块内存区域进行一次大清洗(FullGC),腾出内存,为之后的对象创建,程序运行腾地方。

清理Eden区和Survivor区叫Minor GC;清理Old区叫Major GC;清理整个堆空间—包括年轻代和老年代叫Full GC。

4、jvm建议配置

-XX:MetaspaceSize=128M -XX:MaxMetaspaceSize=256M -Xms256m -Xmx256m
设置元空间的初始值和最大值,设置堆空间的初始值和最大值。

MetaspaceSize要设置为128M?堆内存初始值Xms设置为256M而不是512M?
根据jdk官网的建议

Java堆大小设置,Xms 和 Xmx设置为老年代存活对象的3-4倍,即FullGC之后的老年代内存占用的3-4倍
永久代 PermSize和MaxPermSize(元空间)设置为老年代存活对象的1.2-1.5倍。(1.8以后彻底抛弃了)
年轻代Xmn的设置为老年代存活对象的1-1.5倍。
老年代的内存大小设置为老年代存活对象的2-3倍
类加载统计:
jstat -class pid(进程号)

Loaded | Bytes | Unloaded | Bytes | Time
—| —|--- |— |—
9881 | 17877.5 | 0 | 0.0 | 43.05
加载class的数量|所占用空间大小|未加载数量|未加载占用空间|时间

编译统计
jstat -compiler pid(进程号)
CompiledFailedInvalidTimeFailedTypeFailedMethod
1735     | 0       |0   | 14.09    |      0      

编译数量| Failed:失败数量| Invalid:不可用数量|Time:时间|FailedType:失败类型|FailedMethod:失败的方法

垃圾回收统计
jstat -gc pid(进程号)
S0CS1CS0US1UECEUOCOUMCMUCCSCCCSUYGCYGCTFGCFGCTGCT
第一个幸存区的大小第二个幸存区的大小第一个幸存区的使用大小第二个幸存区的使用大小伊甸园区的大小伊甸园区的使用大小老年代大小老年代使用大小方法区大小方法区使用大小压缩类空间大小压缩类空间使用大小年轻代垃圾回收次数年轻代垃圾回收消耗时间老年代垃圾回收次数老年代垃圾回收消耗时间垃圾回收消耗总时间
堆内存统计
jstat -gccapacity pid(进程号)
NGCMNNGCMXNGCS0CS1CECOGCMNOGCMXOGCOCMCMNMCMXMCCCSMNCCSMXCCSCYGCFGC
新生代最小容量新生代最大容量当前新生代容量第一个幸存区大小第二个幸存区的大小伊甸园区的大小老年代最小容量老年代最大容量当前老年代大小当前老年代大小最小元数据容量最大元数据容量当前元数据空间大小最小压缩类空间大小最大压缩类空间大小当前压缩类空间大小年轻代gc次数老年代GC次数
新生代垃圾回收统计
jstat -gcnew pid(进程号)
S0CS1CS0US1UTTMTTDSSECEUYGCYGCT
第一个幸存区大小第二个幸存区的大小第一个幸存区的使用大小第二个幸存区的使用大小对象在新生代存活的次数对象在新生代存活的最大次数期望的幸存区大小伊甸园区的大小伊甸园区的使用大小年轻代垃圾回收次数年轻代垃圾回收消耗时间
新生代内存统计
jstat -gcnewcapacity pid(进程号)
NGCMNNGCMXNGCS0CMXS0CS1CMXS1CECMXECYGCFGC
新生代最小容量新生代最大容量当前新生代容量最大幸存1区大小当前幸存1区大小最大幸存2区大小当前幸存2区大小最大伊甸园区大小当前伊甸园区大小年轻代垃圾回收次数老年代回收次数
老年代垃圾回收统计
jstat -gcold pid(进程号)
MCMUCCSCCCSUOCOUYGCFGCFGCTGCT
方法区大小方法区使用大小压缩类空间大小压缩类空间使用大小老年代大小老年代使用大小年轻代垃圾回收次数老年代垃圾回收次数老年代垃圾回收消耗时间垃圾回收消耗总时间
老年代内存统计
jstat -gcoldcapacity pid(进程号)
OGCMNOGCMXOGCOCYGCFGCFGCTGCT
老年代最小容量老年代最大容量当前老年代大小老年代大小年轻代垃圾回收次数老年代垃圾回收次数老年代垃圾回收消耗时间垃圾回收消耗总时间
元数据空间统计
jstat -gcmetacapacity pid(进程号)
MCMNMCMXMCCCSMNCCSMXCCSCYGCFGCFGCTGCT
最小元数据容量最大元数据容量最大元数据容量最小压缩类空间大小最大压缩类空间大小最大压缩类空间大小年轻代垃圾回收次数老年代垃圾回收次数老年代垃圾回收消耗时间垃圾回收消耗总时间
总结垃圾回收统计
jstat -gcutil pid(进程号) 
S0S1EOMCCSYGCFGCFGCTGCT
幸存1区当前使用比例幸存2区当前使用比例伊甸园区使用比例老年代使用比例元数据区使用比例压缩使用比例年轻代垃圾回收次数老年代垃圾回收次数老年代垃圾回收消耗时间垃圾回收消耗总时间
JVM编译方法统计
jstat -printcompilation pid(进程号)
CompiledSizeTypeMethod
最近编译方法的数量最近编译方法的字节码数量最近编译方法的编译类型方法名标识

以上是关于jvm的主要内容,如果未能解决你的问题,请参考以下文章

JVM类加载续

JVM调优参数整理

JVM参数说明

JVM 类的加载

JVM 类的加载

类的加载连接和初始化