Analysis and Solution of Soaring Memory of Spring Boot Application in Docker Environment

Spring Boot Introduction

A simple Spring Boot application is used by almost only one user, and the memory reaches 1.2G, which is terrible

Spring Boot application memory soars


A simple Spring Boot application is used by almost only one user, and the memory reaches 1.2G, which is terrible
Service status

Since there were few services and sufficient server resources, many services were started without JVM parameters (legacy issues). The result is that each service startup takes up 1.2G-2G of memory, and some services can't use that much at all. So, how is the JVM memory configured in Spring Boot if the JVM memory parameter is not set?

Spring BootJVM default memory settings


When running a Spring Boot project, if the JVM memory parameter is not set, Spring Boot will use the JVM's own default configuration strategy by default. In the case of sufficient resources, developers do not care much about memory settings. But once it comes to resource shortage and JVM optimization, then you need to understand the default JVM memory configuration strategy.
The most common settings regarding JVM memory are initial heap size (- Xms ) and maximum heap memory (- Xmx ). Many people are too lazy to set it, but use the default value of the JVM. Especially in the development environment, if there are many microservices started, the memory will be burst.

Spring Boot.The JVM default memory configuration strategy is divided into two scenarios, a large memory space scenario and a small memory space scenario (less than 192M).
Taking 4GB of memory as an example, the initial heap memory size and the maximum heap memory size are as follows:

Spring Boot.By default, the maximum heap memory occupies 1/4 of the physical memory , if the application exceeds this limit, an OutOfMemoryError exception will be thrown. The initial heap memory size is 1/64 of physical memory .
If the application runs on a mobile phone or the physical memory is less than 192M, the default initial heap memory size and maximum heap memory size of the JVM are as follows:

The maximum heap memory is 1/2 of the physical memory, and the initial heap memory size is 1/64 of the physical memory, but when the initial heap memory is at least 8MB, it will be 8MB.

When the default free heap memory is less than 40%, the JVM will increase the heap until the maximum limit of - Xmx ; when the free heap memory is greater than 70%, the JVM will reduce the heap until the minimum limit of - Xms .
Therefore, the server generally sets -Xms , -Xmx equal to avoid resizing the heap after each GC. An object's heap memory is reclaimed by an automatic memory management system called the garbage collector .

The maximum heap memory is the upper limit of the memory used by the JVM, and it is as much as it is used in the actual running process. By default, the maximum amount of space allocated to the young generation is one-third of the total heap size .

Spring Boot.In response to the initial problem, if each program is started according to the default configuration, when multiple applications are deployed on a server, there will be a shortage of memory, resulting in a certain amount of waste. The simplest operation is to add the corresponding jvm memory setting parameters when executing java -jar startup.
java -Xms64m -Xmx128m -jar xxx.jar
The project uses Docker deployment, let's first look at the original Dockerfile file

EXPOSE 8061

ADD target/certif-system-2.1.0.jar /certif-system-2.1.0.jar

ENTRYPOINT ["java", "-jar","/certif-system-2.1.0.jar"]

Spring Boot.optimization
Limit JVM memory

Spring Boot will pass any environment variables to the application - but our JAVA_OPTS is not for the application, but for the Java runtime itself. So we need to use the $JAVA_OPTS variable to exec java . This requires some small changes to the Dockerfile :
ENTRYPOINT exec java $JAVA_OPTS -jar app.jar
Run the docker run command
It means that the JAVA_OPTS parameter information in the environment variable is overwritten by -e reset at runtime.
docker run -e JAVA_OPTS='-Xmx1344M -Xms1344M -Xmn448M - XX:MaxMetaspaceSize =192M - XX:MetaspaceSize =192M'

java.security.egd role
SecureRandom is widely used in various components of java and can reliably generate random numbers . However, in scenarios where a large number of random numbers are generated, the performance will be lower. At this time, you can use "- Djava.security.egd =file:/dev/./ urandom " to speed up the random number generation process.
It is recommended to specify the random number generator as /dev/./urandom when using a lot of random numbers .
Please pay attention to the fourth line of source code below for the cause of the bug. If the java.security.egd parameter specifies file:/dev/random or file:/dev/urandom, the parameterless NativeSeedGenerator constructor is called, and the parameterless The constructor will use file:/dev/random by default. The code of openjdk is different from the code of hotspot. Openjdk does not use this variable when generating random numbers later.

Related Articles

Explore More Special Offers

  1. Short Message Service(SMS) & Mail Service

    50,000 email package starts as low as USD 1.99, 120 short messages start at only USD 1.00