How to manage Spring Boot and Spring Cloud application memory?

Memory Management

In the overall application architecture, in a non-production environment, generally 1GB or 2GB of RAM is sufficient. If we divide this application into 20 or 30 independent microservices, it is difficult to expect that the RAM will remain around 1GB or 2GB. Especially if we use Spring Cloud.

First, prepare three services, Eureka service + two simple microservices that provide REST API, and register the microservice to Eureka. Here, the memory usage of these applications is not limited in any way.

Tip: An example of building a simple Spring Cloud application: https://www.ictgu.cn/share/6644e468

As you can see in the picture below, the three microservices take up roughly 1.5GB of RAM memory on the computer. These three services are the simplest applications, and there is basically no data processing. For such memory consumption, it is obviously not ideal. The minimum RAM usage is for Eureka
discovery services, and the maximum is for initializing declarative clients to call APIs of other services.

Unlimited memory usage

The memory usage is as shown in the chart made by JProfiler. As shown in the figure, memory usage is affected by the heap, which consumes a lot of space compared to non-heap.

Heap

Non-Heap

Of course, the first obvious question is whether we need space to run our microservice application on the heap. The answer is no, we don't. Now, let's briefly introduce
how to perform the memory management process in Java 8.

We can divide the JVM memory into two different parts: Heap and Non-Heap . As shown in the figure above, the size of our microserver is size (~ 600MB). In turn, JVM memory of the young generation (Young Generation) , old years (Old Generation) components. All newly created objects are in the young generation. When the young generation is filled up, Minor GC is performed . To be more precise, some of these objects located in the young generation become Eden Space . Minor GC moves all still-used objects from Eden Space to Survivor 0 . Perform the same process for Survivor 0 and Survivor 1 spaces. All objects that survived many cycles in the GC were moved to the old generation memory space. Where to remove objects is the responsibility of Major GC . In order to better understand the following figure, when running the java -jar command, you can use the following parameters to set the memory limit of Java Heap:

  • -Xms – the initial heap size when the JVM starts
  • -Xmx – maximum heap size
  • -Xmn -the size of the young generation, the rest of the space is the old generation

JVM memory

The second part of the JVM memory, from our point of view, the above picture is slightly unimportant, it is Non-Heap. Non-Heap includes the following parts:

  • Thread Stacks : Space for all running threads. You can use the -Xss parameter to set the maximum thread size.
  • Metaspace : It replaces PermGem (Java 7 is part of the JVM heap). In Metaspace, all classes and methods are loaded through the application. Looking at the number of packages included in Spring Cloud, we will not save a lot of memory here. Metaspace size can be managed by setting -XX: MetaspaceSize and -XX: MaxMetaspaceSize parameters.
  • Code Cache : This is the space for native code (such as JNI) or Java methods compiled into native code by the JIT (just-in-time) compiler. Maximum size setting -XX: ReservedCodeCacheSize parameter.
  • Compressed Class Space : Use -XX: CompressedClassSpaceSize is set to the maximum memory reserved for the compressed class space.
  • Direct NIO Buffers

More simply, Heap is for objects and Non-Heap is for classes. It is conceivable that when our application Non-Heap is larger than Heap, we can end this situation. First, let's run our service discovery with the following parameters. In my opinion, if you start Eureka with Tomcat embedded on Spring Boot, these configurations are the lowest values.

-Xms16m \
-Xmx32m \
-XX:MaxMetaspaceSize=48m \
-XX:CompressedClassSpaceSize=8m \
-Xss256k \
-Xmn8m \
-XX:InitialCodeCacheSize=4m \
-XX:ReservedCodeCacheSize=8m \
-XX:MaxDirectMemorySize=16m

If you use REST API microservices (with Feign or Ribbon), we need to increase some values:

-Xms16m \
-Xmx48m \
-XX:MaxMetaspaceSize=64m \
-XX:CompressedClassSpaceSize=8m \
-Xss256k \
-Xmn8m \
-XX:InitialCodeCacheSize=4m \
-XX:ReservedCodeCacheSize=8m \
-XX:MaxDirectMemorySize=16m

According to the above configuration, JProfiler generated the following chart. The difference is the startup and request processing time. Compared to earlier settings, the application runs slower. Of course, I will not set such parameters in a production environment.

Heap

Non-Heap

The current total memory usage is as follows. Microservices still have the largest memory footprint, while Eureka has the smallest.

Low configuration memory usage

I also tried to run Eureka applications using different web containers. You can pom.xmleasily change the web container by including the following dependencies in the file.

Use Undertow

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

Use Jetty

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

Ranking of results: Undertow (116MB), Tomcat (122MB), Jetty (128MB).
This test is only performed on the Eureka service without registering any microservices.

End of sentence

Links to Java resources: https://pan.baidu.com/s/1pUCCPstPnlGDCljtBVUsXQ Password: b2xc
More information: Selected Alibaba Java, architecture, and microservices selected materials in 2020, plus v ❤

Reprinted, please keep the original address, thank you ~

Guess you like

Origin www.cnblogs.com/Alandre/p/12729489.html