前言

在网上查了很多如何配置JVM参数的解说文章,然而生产环境里JVM参数的值到底配置为多少,却没能失去一个具体的标准;的确,生产环境受到各方面的影响,设置适合的JVM参数切实比拟艰难,然而本文将会给大家一个绝对正当的参数设置指标。

本文主线

①、JVM运行时数据区剖析

②、JVM参数设置时的留神点

③、简略的GC垃圾回收过程形容

④、最终JVM参数配置指南

本文为转载文章,原作者:蓝山牧童, 原文地址:jdk1.8——jvm剖析与调优

JVM运行时数据区剖析

上面将次要剖析下 1.7、1.8 两个不同的JDK版本下的JVM运行时数据区。

JDK1.7及以前

JDK 1.7及以前,Java 类信息、常量池、动态变量都存储在 Perm(永恒代)里。类的元数据和动态变量在类加载的时候调配到 Perm,当类被卸载的时候垃圾收集器从 Perm 解决掉。

JDK1.8

JDK 1.8 的对 JVM 架构的革新将类元数据放到 本地内存中 ,另外,将 常量池和动态变量 放到 Java 堆里。HotSopt VM 将会为类的元数据明确调配和开释本地内存。

在这种架构下,类元信息就冲破了原来 -XX:MaxPermSize 最大办法区大小参数的限度,所以PermSize的JVM配置参数也是有效的,当初能够应用更多的本地内存。

这样就从肯定水平上解决了在运行时应用反射、代理等操作生成的大量 类实例 的问题,从而极大的升高了触发Full GC的问题,以及升高了呈现 OutOfMemoryError: PermGen 办法区内存溢出的问题。

JDK1.7的JVM局部运行时数据区展现

干货内容:

能够发现最显著的一个变动是元空间从 虚拟机转移到本地内存 ;默认状况下,元空间的大小仅受本地内存的限度。这意味着当前简直不再会因为永恒代空间不够而抛出OOM异样了。

jdk1.8以前版本的class和jar包数据存储在permGen上面 ,permGen大小是固定的,而且我的项目之间无奈共用私有的class,所以很容易碰到OOM异样。

改成metaSpaces后,各个我的项目会共享同样的class内存空间,比方多个我的项目都援用了apache-common包,在metaSpaces中只会存储一份apache-common的class,进步了内存的利用率,垃圾回收更有效率。

JVM参数设置的留神点

1、在jdk1.7及以前,生产环境个别有如下配置:

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

示意在JVM里存储Java类信息,常量池和动态变量的 永恒代(办法区) 区域初始大小为512M,最大为1024M。在我的项目启动后,这个值是固定的,如果我的项目 class(类实例) 过多,很可能会导致OutOfMemoryError: PermGen异样。

降级JDK1.8之后,下面的perm配置曾经变成:

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

元空间MetaspaceSize如果不做配置,通过jinfo查看默认MetaspaceSize大小(约21M),MaxMetaspaceSize最大元空间则很大很大,后面说过MetaSpace只受本地内存大小限度

jinfo -flag MetaspaceSize 1234  #后果为:-XX:MetaspaceSize=21807104jinfo -flag MaxMetaspaceSize 1234 #后果为:-XX:MaxMetaspaceSize=18446744073709547520

干货内容:

MetaspaceSize触发FullGC的阈值,默认约为21M,如做了配置,最小阈值为自定义配置大小。空间应用达到阈值,触发FullGC,同时对该值扩充。当然如果元空间理论应用小于阈值,在GC的时候也会对该值放大。

MaxMetaspaceSize为元空间的最大值,如果设置太小,就会和下面提到的一样,可能会导致频繁FullGC,甚至OOM。

GC 垃圾回收过程

首先贴上一张摘抄自网上的大图,联合此大图能够更加清晰的阐明GC的过程:

垃圾回收过程:

上面说的GC流程中,新生代中的对象降职到年轻代中的条件是 年龄阀值 ;除此之外还有很多其它的降职条件,前面会再细说。

①、新new的对象都放在Eden区(伊甸园嘛,发明的中央)

②、记住新生代的GC算法是 复制算法 。Eden区满或者快满的时候触发GC时(Minor Gc);在GC刚开始的时候,对象只会存在于Eden区和名为 From 的Survivor区,Survivor区 To 是空的。紧接着进行GC,Eden区中所有存活的对象都会被复制到 To 区,而在 From 区中,仍存活的对象会依据他们的年龄值来决定去向。

③、年龄达到肯定值(年龄阈值,能够通过 -XX:MaxTenuringThreshold 来设置,默认是 15 )的对象会被挪动到年轻代中,没有达到阈值的对象会被复制到Survivor To 区域。

④、通过这次GC后,Eden区和From区曾经被清空。这个时候, From和To 会替换它们的角色,也就是新的 To 就是上次GC前的 From,新的 From 就是上次GC前的 To

⑤、不管怎样,都会保障名为 To 的Survivor区域是空的。Minor GC会始终反复这样的过程,直到 To 区被填满, To 区被填满之后,会将所有对象挪动到年轻代中。

⑥、留神:当在触发Minor GC时,发现堆新生代中还存活的年龄达到阀值的对象的容量,比目前年轻代中残余空间还大的话,阐明年轻代寄存不下,就会间接触发一次Full GC,而不再去触发Minor GC 了。

清理新生代(Eden区和Survivor区)叫Minor GC;清理年轻代(Old区)叫Major GC;清理整个堆空间(年老代和老年代)以及永恒代(办法区)叫Full GC。
再贴一张大图配合了解GC的过程:

新生代对象降职到年轻代的条件:

①、如果对象的大小大于Eden的二分之一会间接调配在old年轻代,如果old也调配不下,会做一次major GC,如果小于Eden的一半然而没有足够的空间,就进行minor GC也就是新生代GC。

②、minor GC后,Survivor依然放不下,则放到Old老年代。

③、动静年龄判断 ,大于等于某个年龄的对象超过了Survivor空间一半 ,大于等于某个年龄的对象间接进入老年代。

JVM参数配置指南

后面三个局部对JVM进行了整体的理解,接下来是本文的重点。

-XX:MetaspaceSize=128M -XX:MaxMetaspaceSize=256M -Xms256m -Xmx256m

文章看下来下面这段配置的意思很简略,设置元空间的初始值和最大值,设置堆空间的初始值和最大值。

为什么MetaspaceSize要设置为128M?为什么堆内存初始值Xms设置为256M而不是512M?

依照Java官网的领导:

①、Java堆大小设置,Xms 和 Xmx设置为老年代存活对象的3-4倍,即Full GC之后的老年代内存占用的3-4倍。

②、永恒代 PermSize和MaxPermSize(元空间)设置为老年代存活对象的1.2-1.5倍。

③、年老代Xmn的设置为老年代存活对象的1-1.5倍。

④、老年代的内存大小设置为老年代存活对象的2-3倍。

应用一个模拟生成环境进行测试运行一段时间后,获取JVM参数数据。而后再进行设置理论的JVM参数;如下用jstat工具查看jvm的状况:

jstat -gc 12345### S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   13824.0 22528.0 13377.0  0.0   548864.0 535257.2  113152.0   46189.3   73984.0 71119.8 9728.0 9196.2     14    0.259   3      0.287    0.546

OU示意老年代所占用的内存为 46189.3 K(大概45M);那么jvm相应的配置参数应该做如下批改:

-XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=64M -Xms180m -Xmx180m

❤ 关注 + 点赞 + 珍藏 + 评论 哟

如果本文对您有帮忙的话,请挥动下您爱发财的小手点下赞呀,您的反对就是我一直创作的能源,谢谢!

您能够VX搜寻【木子雷】公众号,保持高质量原创java技术文章,值得您关注!