【JVM】七、线上系统部署时如何设置JVM内存大小

在我们日常编写代码时,所创建的对象通常是首先在新生代区域进行分配的。然后,当一些方法执行完毕后,大部分位于新生代区域中的对象将不再被引用,从而变成垃圾对象

1、前文回顾

让我们先来回顾一下我们已经学到的知识。现在,大家应该都明白了,在我们日常编写代码时,所创建的对象通常是首先在新生代区域进行分配的。然后,当一些方法执行完毕后,大部分位于新生代区域中的对象将不再被引用,从而变成垃圾对象。如下图所示:

随着程序的持续执行,新生代区域中会逐渐积累大量对象。这其中,大部分对象都是一些短生命周期的对象,它们在被使用一段时间后,便不再被任何其他对象引用,因此这些对象实际上变成了垃圾对象。然而,由于内存资源是有限的,当新生代区的可用内存不足时,就会触发一次名为Minor GC的垃圾回收机制。Minor GC的主要任务就是清理新生代区中的垃圾对象,即那些不再被引用的旧对象。通过回收这些垃圾对象,Minor GC能够为新生区腾出大量的内存空间,以便用于存储新创建的对象。如下图所示:

image-20240418162720839

对于那些在长周期内持续存活的对象,它们将在新生代中度过多个垃圾回收周期。每一次成功逃过垃圾回收,它们的年龄将增加一岁。随着时间的推移,当对象达到十岁以上的“老年”阶段时,它们将被迁移到老年代中。如下图:

image-20240418162822290

好的,至此为止,我们暂时不考虑一些特殊情况,大家应该已经对JVM中基本的内存分配原理有了清晰的了解。

2、跟JVM内存相关的几个核心参数图解

在JVM内存分配中,有几个参数是比较核心的,如下所示。
-Xms:Java堆内存的大小
-Xmx:Java堆内存的最大大小
-Xmn:Java堆内存中的新生代大小,扣除新生代剩下的就是老年代的内存大小了
-XX:PermSize:永久代大小
-XX:MaxPermSize:永久代最大大小
-Xss:每个线程的栈内存大小

下面我们对上述参数来进行一一说明。
-Xms和-Xmx,分别用于设置Java堆内存的刚开始的大小,以及允许扩张到的最大大小。对于这对参数,通常来说,都会设置为完全一样的大小。这两个参数,是用来限定Java堆内存的总大小的,如下图。

image-20240412084125785

-Xmn,这个参数也是很常见的,它用来设置Java堆内存中的新生代的大小,然后扣除新生代大小之后的剩余内存就是给老年代的内存大小,我们看下图:

image-20240412084318732

-XX:PermSize和-XX:MaxPermSize,分别限定了永久代大小和永久代的最大大小
通常这两个数值也是设置为一样的,至于原因,请看后面结合案例的文章分析。
如果是JDK 1.8以后的版本,那么这俩参数被替换为了-XX:MetaspaceSize和-XX:MaxMetaspaceSize,但是大家至少得知道,这两个参数限定了永久代的大小,如下图所示:

image-20240412084508386

-Xss,这个参数限定了每个线程的栈内存大小
大家都很清楚,每个线程都有一个自己的虚拟机栈,然后每次执行一个方法,就会将方法的栈帧压入线程的栈里,方法执行完毕,那么栈帧就会从线程的栈里出栈,如下图:

image-20240412084629677

3、如何在启动系统的时候设置JVM参数?

那么现在大家结合图示都知道了JVM内存各个区域的大小该使用什么参数来设置,那么到底怎么设置呢?

假设你使用的是IntelliJ IDEA来开发代码,如果要在这种开发IDE里启动一个程序,然后设置JVM参数,那么就需要对按照下面的步骤来设置:
首先右击你写好的一个带main()方法的类,他有一个菜单栏,里面有一个“Debug as”选项,鼠标移动进入,会看到一个“Debug Configuration”选项,接着会看到下面的面板。

image-20240412085200404

这个面板里有一个“Arguments”的选项,点击他,会看到下面的图。然后在“VM arguments”中输入你的JVM参数即可
比如你可以按照下面的示例来设置,-Xms之类的参数直接后面跟上你要设置的内存大小,多少M即可。
但是-XX:PermSize这种格式的参数,需要跟一个“=”符号,跟上你要设置的内存大小即可。

image-20240412085133564

那么如果是在线上部署系统应该如何设置JVM参数呢?
其实都很简单,比如说采用“java -jar”的方式启动一个jar包里的系统,那么就可以采用类似下面的格式:
java -Xms512M -Xmx512M -Xmn256M -Xss1M -XX:PermSize=128M -XX:MaxPermSize=128M -jar App.jar
如果是现在非常流行的那种启动Spring Boot开发的系统呢?其实都是类似的,大家自行翻阅一下Spring Boot的文档即可。