jvm调优 - 堆空间各区域大小如何划分配置?

发布时间:2022-03-01 10:51:33 作者:yexindonglai@163.com 阅读(606)

jvm内存结构

首先,我们来看看jvm堆内存结构,分别新生代、老年代,其中新生代又分为eden区和Survivore区,Survivore区又分为from区和to区;
在这里插入图片描述

除了堆内存之外,Java 虚拟机还有一个 非堆 的空间,这个空间由所有线程共享的方法区。方法区(也叫永久代)属于非堆内存。它存储每个类结构,如运行时常数池、字段和方法数据,以及方法和构造方法的代码。它是在 Java 虚拟机启动时创建的。
在这里插入图片描述

各区域的默认值

堆内存

堆空间初始值

由-Xms指定,默认是物理内存的1/64。比如我电脑内存是16G,由此得出公式为:16*1024/64=256M

堆空间最大值

由-Xmx指定,默认是物理内存的1/3。比如我电脑内存是16G,由此得出公式为:16/4=4G

老年代

占用整个堆内存2/3的空间,比如我目前堆内存是4G,由此得出公式为:4*1024*(2/3)$\approx$2730

新生代

通过以下参数设置

  1. - `-XX:NewSize=256m` 设置新生代初始内存
  2. - `-XX:MaxNewSize=256m` 设置新生代最大内存
  3. - `-Xmn256m` NewSizeMaxNewSize设为一致。256m
  4. - 新生代默认占用整个堆内存`1/3`的空间,比如我目前堆内存是4G,由此得出公式为:`4*1024*(1/3)`$\approx$`1365`,另外新生代实际可用的内存为 9/10 ( 90% ),

新生代和老年代比例

新老年代默认比例为:1:2,也就是说老年代会比新生代多一倍的容量,通过参数 -XX:NewRatio=3,设置新生代与老年代的比值。设置为3,则新生代与老年代所占比值为1:3,

Survivore区

由于Survivore分为from区和to区,且这2个区域的大小是一样的,所以eden、from、to的比例为8:1:1;如果设置参数-XX:SurvivorRatio=7,则eden、from、to的比例为7:1.5:1.5

eden区

新生代减去2个Survivor区的内存大小就是Eden的大小

  • 默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;
  • 空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。

非堆内存

方法区:

通过-XX: PermSize=128m设置持久代初始内存大小128M,-XX:MaxPermSize=512m设置持久代最大内存大小512M,
MaxPermSize缺省值和-server -client选项相关,-server选项下默认MaxPermSize为64m,-client选项下默认MaxPermSize为32m。

栈内存

通过-Xss1m设置,JDK5.0以后每个线程栈大小为1M,JDK1.5以前每个线程栈大小为256K,每个线程都会产生一个栈。在相同物理内存下,减小这个值能生成更多的线程。如果这个值太小会影响方法调用的深度,所以当递归调用太深的时候,就有可能耗尽栈空间,爆出StackOverflow的错误。

在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一 个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

线程栈的大小是个双刃剑
· 如果设置过小,可能会出现栈溢出,特别是在该线程内有递归、大的循环时出现溢出的可能性更大,
· 如果该值设置过大,就有影响到创建栈的数量,如果是多线程的应用,就会出现内存溢出的错误.

堆空间各区域大小划分

在调优之前,我们首先要知道目前项目中长期存活的对象占用了多大的内存空间,也就是老年代的空间有多少活跃数据,这个数据可以通过查看GC日志得到,就是每次fullgc后老年代还有多少空间,因为每次的值都不一样,所以我们可以取一个平均值;得到这个平均值后,就可以设置堆空间区域大小了,下图是一个参考标准,接下来我们就以这参考图来设置各空间的大小
在这里插入图片描述
比如我项目中老年代活跃数据的大小为500M,在这里我们都取一个最大值,那么我们就可以这样设置

  • 总大小:设置堆空间总大小公式为: 500*4=2000M,将堆内存最大和初始内存都设为2000,jvm参数为:-Xmx2000m -Xms2000m
  • 新生代:设置堆空间的新生代大小公式为:500*1=500M,jvm参数为:-XX:NewSize=500m -XX:MaxNewSize=500m
  • 老年代:设置堆空间的老年代大小公式为:500*3=1500:因为老年代只能设置比例,所以我们设置新生代和老年代的比例为1:3,jvm参数为:-XX:NewRatio=3,这样经过换算下来,老年代就有 1500M 的空间了
  • 永久代/元空间 :注意这里取值必须是full gc 后的永久代空间,比如经过GC清理后,我的永久代活跃数据为100m,那我们就设置为150M;jvm参数为:-XX: PermSize=150m --XX: PermSize=150m

以上调优是为大家做一个标准模板,实际上调优的话还得通过具体环境和条件在计算出配置的大小;当然,在大部分项目情况下也已经够用了;

关键字Java