启动Spring Boot时,如果不设置内存参数会如何?

简介: 启动Spring Boot时,如果不设置内存参数会如何?

最近正在进行从Spring Boot往Spring Cloud上改造升级。之前部署的应用程序比较少,还没什么问题。当Spring Cloud项目逐步新增之后,问题就爆发了,服务器内存不够用了。而现有的用户体量也没必要对服务器再次进行升级,于是就开始着手Spring Boot启动时JVM内存配置的优化。


服务现状

由于之前服务比较少,服务器资源充足,许多服务启动时都未添加JVM参数(遗留问题)。结果就是每个服务启动都占用了1.5G-2G的内存,有些服务的体量根本用不了这么多。那么,在Spring Boot中如果未设置JVM内存参数时,JVM内存是如何配置的呢?


JVM默认内存设置

当运行一个Spring Boot项目时,如果未设置JVM内存参数,Spring Boot默认会采用JVM自身默认的配置策略。在资源比较充足的情况下,开发者倒是不太用关心内存的设置。但一旦涉及到资源不足,JVM优化,那么就需要了解默认的JVM内存配置策略。


关于JVM内存最常见的设置为初始堆大小(-Xms)和最大堆内存(-Xmx)。很多人懒得去设置,而是采用JVM的默认值。特别是在开发环境下,如果启动的微服务比较多,内存会被撑爆。


而JVM默认内存配置策略分两种场景,大内存空间场景和小内存空间场景(小于192M)。


以4GB内存为例,初始堆内存大小和最大堆内存大小如下图:


image.png默认情况下,最大堆内存占用物理内存的1/4,如果应用程序超过该上限,则会抛出OutOfMemoryError异常。初始堆内存大小为物理内存的1/64。

如果应用程序运行在手机上或物理内存小于192M时,JVM默认的初始堆内存大小和最大堆内存大小如下图:image.png最大堆内存为物理内存的1/2,初始堆内存大小为物理内存的1/64,但当初始堆内存最小为8MB,则为8MB。


默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制。因此,服务器一般设置-Xms、-Xmx相等以避免在每次GC后调整堆的大小。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。


其中最大堆内存是JVM使用内存的上限,实际运行过程中使用多少便是多少。默认,分配给年轻代的最大空间量是堆总大小的三分之一。


针对最开始的问题,如果每个程序都按照默认配置启动,一台服务器上部署多个应用时,就会出现内存吃紧的情况,造成一定的浪费。最简单的操作就是在执行java -jar启动时添加上对应的jvm内存设置参数。


java -Xms64m -Xmx128m -jar xxx.jar

1

切记参数要防止-jar参数之前。否则会被当做系统参数而无效。


当然在排查JVM的使用情况时,还会用到以下相关操作。


查看系统默认内存设置

通过上面的描述我们可以看到,不同的系统配置,JVM使用的内存是不同的。我们可以通过Java命令自带的功能来查看默认的内存设置。


在Linux操作系统下,输入如下命令:


java -XX:+PrintFlagsFinal -version | grep HeapSize

1

输入效果如下:


image.png在Windows操作系统下,输入如下命令:


java -XX:+PrintFlagsFinal -version | findstr HeapSize

1

查看运行时内存情况

当应用程序运行时,如果我们想查看程序的运行情况,可通过以下几种方式来查询不同维度的数据。


查看正在运行的jvm服务

可以通过jps命令查看正在运行的jvm服务。


appledeMacBook-Pro:~ apple$ jps

51972 EurekaApplication

51973 Launcher

51976 Jps

1

2

3

4

其中前面的数字为进程号。


查看某进程的JVM情况

可以使用jstat命令查询具体进程的GC情况。


appledeMacBook-Pro:~ apple$ jstat -gc 51972 5000

S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT

14336.0 14336.0  0.0   14312.7 145920.0 100055.3  175104.0   17500.2   52136.0 48999.3 7600.0 6958.7      9    0.058   2      0.050    0.107

14336.0 14336.0  0.0   14312.7 145920.0 100055.3  175104.0   17500.2   52136.0 48999.3 7600.0 6958.7      9    0.058   2      0.050    0.107

14336.0 14336.0  0.0   14312.7 145920.0 100055.3  175104.0   17500.2   52136.0 48999.3 7600.0 6958.7      9    0.058   2      0.050    0.107

1

2

3

4

5

其中51972是进程号,5000为刷新时间。


对应数据项的含义:


S0C:年轻代中第一个survivor(幸存区)的容量 (字节)

S1C:年轻代中第二个survivor(幸存区)的容量 (字节)

S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)

S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)

EC:年轻代中Eden(伊甸园)的容量 (字节)

EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)

OC:Old代的容量 (字节)

OU:Old代目前已使用空间 (字节)

YGC:从应用程序启动到采样时年轻代中gc次数

YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)

FGC:从应用程序启动到采样时old代(全gc)gc次数

FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)

GCT:从应用程序启动到采样时gc用的总时间(s)

查看堆栈使用情况

通过jmap命令来查看堆栈的使用情况。


[root@bjb ~]# jmap -heap 10471
Attaching to process ID 10471, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.262-b10
using thread-local object allocation.
Parallel GC with 2 thread(s)
Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 2051014656 (1956.0MB)
   NewSize                  = 42991616 (41.0MB)
   MaxNewSize               = 683671552 (652.0MB)
   OldSize                  = 87031808 (83.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
   capacity = 342360064 (326.5MB)
   used     = 128426952 (122.47748565673828MB)
   free     = 213933112 (204.02251434326172MB)
   37.51224675550943% used
From Space:
   capacity = 4194304 (4.0MB)
   used     = 3458288 (3.2980804443359375MB)
   free     = 736016 (0.7019195556640625MB)
   82.45201110839844% used
To Space:
   capacity = 4194304 (4.0MB)
   used     = 0 (0.0MB)
   free     = 4194304 (4.0MB)
   0.0% used
PS Old Generation
   capacity = 216006656 (206.0MB)
   used     = 86142704 (82.15208435058594MB)
   free     = 129863952 (123.84791564941406MB)
   39.879652597371816% used
22325 interned Strings occupying 2361920 bytes.

关于具体参数就不在这里解释了。

小结

项目中往往一些被忽视的问题,深究起来,排查起来,反而能串联起来一系列的知识点和技能,或许这就是深入思考与探索的魅力所在。你在项目的使用过程中是否也遇到类似的问题,是否也深入探究过么?


目录
相关文章
|
Dubbo Java 应用服务中间件
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
|
前端开发 Java Unix
【NiFi】(二)三分钟搞定 NiFi 安装与简单使用!
【NiFi】(二)三分钟搞定 NiFi 安装与简单使用!
2833 0
【NiFi】(二)三分钟搞定 NiFi 安装与简单使用!
|
11月前
|
存储 数据可视化 数据挖掘
使用Python进行数据分析和可视化
本文将引导你理解如何使用Python进行数据分析和可视化。我们将从基础的数据结构开始,逐步深入到数据处理和分析的方法,最后通过实际的代码示例来展示如何创建直观的数据可视化。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧。让我们一起探索数据的世界,发现隐藏在数字背后的故事!
325 5
|
11月前
|
Java API 持续交付
apache nifi 如何进行二次开发?
【10月更文挑战第23天】apache nifi 如何进行二次开发?
539 2
|
安全 Java 开发者
开发者必看!@Resource与private final的较量,Spring Boot注入技巧大揭秘,你不可不知的细节!
【8月更文挑战第29天】Spring Boot作为热门Java框架,其依赖注入机制备受关注。本文通过对比@Resource(JSR-250规范)和@Autowired(Spring特有),并结合private final声明的字段注入,详细探讨了两者的区别与应用场景。通过示例代码展示了@Resource按名称注入及@Autowired按类型注入的特点,并分析了它们在注入时机、依赖性、线程安全性和单一职责原则方面的差异,帮助开发者根据具体需求选择最合适的注入策略。
577 0
|
存储 安全 算法
代码混淆和加固,保障应用程序的安全性
代码混淆是将源代码进行加密和优化,使得反编译者难以理解和还原源代码的过程。通过替换变量名、类名等信息为无意义的字符,代码混淆使得反编译后的代码难以理解和维护,从而提高了应用程序的安全性。 代码加固是对已经混淆的代码进行二次保护,防止破解者通过静态或动态分析手段获取到关键算法和逻辑。代码加固可以添加额外的安全层,包括加密、反调试、反动态调试、反内存dump等,从而增强应用程序的抗攻击能力,以IPA Guard为例,。
|
存储 安全 Linux
从基础到高级:Linux用户与用户组权限设置详解
从基础到高级:Linux用户与用户组权限设置详解
1309 2
|
Java Windows
springboot打成jar包,在windows上运行出现乱码
springboot打成jar包,在windows上运行出现乱码
494 0
|
安全 Linux 网络安全
如何在 Debian VPS 上添加、删除和授予用户 sudo 权限
【4月更文挑战第2天】在 Debian 系统中,创建新用户可降低管理风险。新用户默认无管理员权限,可通过 `adduser` 命令添加。要让用户体验 sudo 提升权限,需将其加入 `sudo` 组,如 `usermod -aG sudo newuser`。用户可通过 `ssh` 或 `su -` 切换登录。了解这些基础操作能有效管理和维护服务器。
482 0
|
SQL 搜索推荐 关系型数据库
Windows 系统彻底卸载 SQL Server 通用方法
Windows 系统彻底卸载 SQL Server 通用方法
1332 0
Windows 系统彻底卸载 SQL Server 通用方法