When you have 200 concurrent users hitting a single-threaded service, you’ll see OutOfMemoryError exceptions due to inefficient garbage collection. This is because the default garbage collector in Java is not optimized for high-concurrency and large heaps.

TL;DR: In this tutorial, you’ll learn how to implement Java garbage collection, solve memory leaks, and improve application performance. You’ll understand the different types of garbage collectors, how to configure them, and how to troubleshoot common issues.

## Prerequisites * Java version: 17 or later * Spring Boot version: 2.7 or later * Maven or Gradle * java and spring-boot-starter dependencies

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

## Understanding Java Garbage Collection Internally The garbage collector is responsible for freeing up memory occupied by objects that are no longer in use. Java provides several types of garbage collectors, including Serial GC, Parallel GC, Concurrent Mark-and-Sweep (CMS) GC, and Garbage-First (G1) GC. Each has its own strengths and weaknesses.

 +---------------+ | Application | +---------------+ | | v +---------------+ | Heap Memory | +---------------+ | | v +---------------+ | Garbage Collector | +---------------+ | | v +---------------+ | Free Memory | +---------------+ 

The following table compares the different types of garbage collectors:

Garbage Collector Description Pros Cons
Serial GC Single-threaded garbage collector Simple, low overhead Slow, not suitable for large heaps
Parallel GC Multi-threaded garbage collector Faster than Serial GC, suitable for large heaps Higher overhead, may cause pauses
CMS GC Concurrent mark-and-sweep garbage collector Low pause times, suitable for real-time systems Higher overhead, may cause memory fragmentation
G1 GC Garbage-first garbage collector Low pause times, suitable for large heaps Higher overhead, may cause memory fragmentation

## Step-by-Step Implementation ### Step 1: Choose a Garbage Collector Choose a garbage collector based on your application’s requirements. For example, if you have a real-time system, you may want to use the CMS GC or G1 GC.

 public class GarbageCollectorExample { public static void main(String[] args) { // Choose a garbage collector System.setProperty("java.lang.gc", "G1"); } } 

### Step 2: Configure the Garbage Collector Configure the garbage collector based on your application’s requirements. For example, you can set the XX:NewRatio option to control the size of the young generation.

 public class GarbageCollectorExample { public static void main(String[] args) { // Configure the garbage collector System.setProperty("XX:NewRatio", "2"); } } 

### Step 3: Monitor the Garbage Collector Monitor the garbage collector to ensure it is working correctly. You can use tools like jconsole or jvisualvm to monitor the garbage collector.

 public class GarbageCollectorExample { public static void main(String[] args) { // Monitor the garbage collector System.out.println("Garbage collector: " + System.getProperty("java.lang.gc")); } } 

Expected output:

 Garbage collector: G1 

## Complete Working Example The following is a complete working example of a Java application that uses the G1 GC garbage collector:

 package com.example.app; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { // Choose a garbage collector System.setProperty("java.lang.gc", "G1"); // Configure the garbage collector System.setProperty("XX:NewRatio", "2"); // Monitor the garbage collector System.out.println("Garbage collector: " + System.getProperty("java.lang.gc")); SpringApplication.run(Application.class, args); } } 

File structure:

 com example app Application.java config ApplicationConfig.java controller ApplicationController.java repository ApplicationRepository.java service ApplicationService.java 

Sample curl request:

 curl -X GET "http://localhost:8080/example" 

Response:

 { "message": "Hello World" } 

## Common Mistakes and How to Fix Them ### Mistake 1: Not Closing the Connection Pool Not closing the connection pool can cause memory leaks.

 public class ConnectionPoolExample { public static void main(String[] args) { // WRONG - causes memory leak Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/example", "username", "password"); // ... } } 

Error message:

 java.lang.OutOfMemoryError: Java heap space 

Fixed code:

 public class ConnectionPoolExample { public static void main(String[] args) { // FIXED - closes connection pool Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/example", "username", "password"); try { // ... } finally { connection.close(); } } } 

## Performance and Production Tips

Production tip: Set hikari.maximum-pool-size to 10 for a 4-core server. Default is 10, but you may need to adjust based on your application’s requirements.

Production tip: Use spring-boot-starter-actuator to monitor your application’s performance and adjust configuration as needed.

## Testing The following is an example of a JUnit 5 test for the core logic:

 package com.example.app; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest public class ApplicationTest { @Autowired private ApplicationService applicationService; @Test public void testApplicationService() { // Test the application service String result = applicationService.getMessage(); assertEquals("Hello World", result); } } 

For more information on testing, see Java Algorithms and More Java Tutorials. ## Key Takeaways * Use the G1 GC garbage collector for low pause times and high throughput. * Configure the garbage collector based on your application’s requirements. * Monitor the garbage collector to ensure it is working correctly. * Use spring-boot-starter-actuator to monitor your application’s performance and adjust configuration as needed. * Test your application thoroughly to ensure it is working correctly. * For more information on Java, see the Java Tutorials Hub and SOLID Design Principles in Java.

Read Next

Pillar Guide: Java Tutorials Hub — explore the full learning path.

Source Code on GitHub
java-examples — Clone, Star & Contribute

You Might Also Like

Java Multithreading and Concurrency Interview Questions with Answers
Java 21 Structured Concurrency Tutorial for Beginners
Mastering Spring Boot Unit Testing with JUnit 5 and Mockito


Leave a Reply

Your email address will not be published. Required fields are marked *