The principle and trigger conditions of Full GC
principle
- Mark-Clear: First iterate through all objects, mark accessible objects, and then clear unreachable objects.
- Copy algorithm: divide the memory into two parts, using only part of it at a time. When this part of memory runs out, copy the surviving object to another part and clean up the current part.
- Tag-tidy: Similar to Tag-clear, but after clearing useless objects, the remaining objects are compressed to avoid memory fragmentation issues.
Full GC involves cleaning up the entire heap, including the new generation, the old generation and the permanent generation/metaspace, which usually results in longer application pauses.
Trigger condition
Insufficient space for the elderly: trying to allocate large objects but not enough space for the elderly.
Permanent generation/metaspace full: Permanent generation in Java 8 and previous versions is full; metaspace in Java 9 and later versions is full.
Explicit call (): Although not recommended, sometimes developers will request garbage collection manually.
Overall heap memory usage is too high: In some cases, the JVM may decide to execute Full GC based on overall heap usage.
Impact on Spring Boot Applications
Frequent Full GC will lead to increased application response time and decreased throughput, especially in high concurrency scenarios.
Things to note
Reasonably set the heap size: adjust -Xms (initial heap size) and -Xmx (maximum heap size) according to the actual needs of the application.
Choose the right garbage collector: new generation garbage collectors such as G1 and ZGC, aiming to reduce the frequency and pause time of Full GC.
Monitoring and analysis: Use Spring Boot Actuator, Prometheus, Grafana and other tools to monitor GC behavior.
Sample code
Example 1: Simulate the Full GC situation in Spring Boot application
@RestController public class MemoryController { @GetMapping("/allocate") public String allocateMemory() { // 1MB of data is allocated for each request byte[] data = new byte[1024 * 1024]; return "Allocated 1MB of memory"; } }
This controller allocates 1MB of memory every time it receives a /allocate request. If a large number of concurrent requests arrive at the same time, the old age space may be quickly exhausted, triggering Full GC.
Example 2: Adjust JVM parameters
GC behavior can be optimized by adjusting JVM startup parameters. For example, add the following parameters on or directly through the command line:
-Xms2g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200
This sets the initial heap size to 2GB, the maximum heap size is 4GB, and enables the G1 garbage collector, with the goal of no more than 200 milliseconds per GC pause.
Example 3: Code Optimization - Reduce unnecessary object creation
Consider multiplexing objects instead of creating new instances every time:
@Service public class MemoryService { private static final int SIZE = 1024 * 1024; // 1MB private byte[] reusableBuffer = new byte[SIZE]; public void processData() { // Use reusableBuffer instead of new array every time } }
Example 4: Asynchronous Processing and Caching
Using Spring's asynchronous support and caching mechanism can also reduce memory pressure:
@Cacheable("expensiveOperationResults") public Result performExpensiveOperation(Input input) { // Perform some time-consuming operations return result; } @Async public CompletableFuture<Void> asyncTask() throws InterruptedException { // Asynchronous execution of tasks return (null); }
Example 5: Monitoring with Spring Boot Actuator
Add dependencies:
<dependency> <groupId></groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
Configure the exposed endpoint:
management: endpoints: web: exposure: include: "*"
You can view information such as GC pause time by visiting http://localhost:8080/actuator/metrics/.
Optimization suggestions
Adjust JVM parameters
Heap size resize: Make sure the heap size is suitable for your application load. A heap that is too large or too small can cause performance problems.
Garbage collector selection: Select the appropriate garbage collector according to the application characteristics. For applications with low latency requirements, consider using ZGC or Shenandoah.
Garbage collection log: Enable garbage collection logs for better understanding and optimization of GC behavior:
-XX:+PrintGCDetails -Xlog:gc*:file=
Code-level optimization
Object pooling: For objects that are frequently created and destroyed, consider using object pooling techniques to reuse objects.
Lazy loading: Avoid unnecessary initialization and use lazy loading to reduce resource consumption at startup.
Batch processing: For tasks that require a large amount of memory operations, consider batch processing to reduce the memory usage of a single operation.
in conclusion
Through understanding the Full GC problems that may arise in Spring Boot applications, we can take a variety of measures to optimize application performance. The key is to rationally configure JVM parameters, select suitable garbage collectors, optimize code to reduce unnecessary object creation, and use features provided by the Spring framework such as asynchronous processing and caching to reduce memory pressure. These strategies can help significantly reduce the frequency and impact of Full GCs and improve overall performance and stability of the application. At the same time, continuous monitoring and analysis of GC behavior is crucial to promptly detecting and solving problems.
This is the article about the scenarios and solutions of Full GC problems that appear in SpringBoot applications. For more relevant SpringBoot Full GC problems, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!