乐趣区

关于jvm:一文让你彻底明白JVM参数该怎么设置

前言

在网上查了很多如何配置 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=21807104
jinfo -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 技术文章,值得您关注!

退出移动版