Journal
Backend 6 min read

Memory Management of Beans in Spring Boot Applications

Understanding scope-wise memory management in Spring: where your beans actually live, how they're retrieved, and why scope choice matters for performance.

Millions of developers use Spring Boot because it makes application development incredibly smooth. You annotate a class with @Component or @Service, and Spring magically manages its lifecycle. It’s so seamless that most developers never stop to ask:

“Where are these objects actually stored? How does Spring fetch them when needed?”

In a simple Java program, the JVM handles class loading, object creation, and memory allocation. But when a Spring Boot application starts, it adds an extra orchestration layer. Instead of directly creating objects, Spring first registers metadata about beans, manages dependencies, and uses mechanisms like caching, proxies, and scopes to optimise retrieval.

Bean scope plays a critical role in defining when and how beans are created, how long they persist, and how they are shared across the application. Choosing the right bean scope is key to optimising resource usage, improving performance, and ensuring efficient memory management. This article delves into how Spring Boot stores and manages beans in memory across different scopes.


What Are Bean Scopes in Spring Boot?

A bean scope defines how and when a bean is created, stored, and shared within the application. By default, Spring manages beans as singletons: only one instance exists within the application context. However, in some cases we need different behaviours, such as creating a new instance for each request or session.

Spring provides five main bean scopes:

  • Singleton: one shared instance for the lifetime of the application
  • Prototype: a new instance created on every request
  • Request: one instance per HTTP request
  • Session: one instance per HTTP session
  • WebSocket: one instance per WebSocket connection

1. Singleton Beans

When a singleton bean is created, it is stored in two main locations:

  • JVM Heap (Actual Object Storage): the physical object instance resides in Java heap memory, just like any regular Java object
  • Singleton Cache: Spring maintains an internal cache inside BeanFactory to store and quickly retrieve singleton instances, preventing unnecessary object creation and allowing fast lookups without recreating the object

Retrieval Process

When an object is requested, Spring:

  1. Checks the Singleton Cache: if the instance exists, it returns it
  2. Creates the bean if not found: only happens for lazy beans or during first-time access

2. Prototype Beans

Prototype beans are created in Java heap memory each time they are requested. Each request triggers a new object instantiation.

Unlike singleton beans, the Spring container does not maintain a long-term cache or any management of these instances once they have been handed over to the requester.

Trade-offs at a Glance

SingletonPrototype
Instance countOneOne per request
Memory usageLowHigher
GC pressureMinimalFrequent allocation
Best forStateless servicesStateful, short-lived objects

Advantages:

  • Good for short-lived objects: ideal for objects that hold temporary or user-specific data

Disadvantages:

  • Increased memory usage: more instances mean higher heap allocation and potential memory overhead
  • Garbage collection load: since objects are not reused, frequent garbage collection may impact performance

3. Request Beans

A request-scoped bean is created and tied to an individual HTTP request. Request-scoped beans are stored in the request attributes of the current HTTP request: the RequestScope implementation within Spring is responsible for managing this storage.

Lifecycle

  1. User sends an HTTP request: Spring Boot identifies this as a new request and sets up the request context
  2. Spring checks if a bean instance already exists for the current request in the request scope registry
  3. If not, creates a new instance using reflection, stores it inside the HTTP request attributes, and returns the bean for use
  4. Once the request is processed and the response is sent, the request scope is destroyed
  5. Spring automatically removes the bean from the registry: the bean becomes eligible for garbage collection

4. Session Beans

Session-scoped beans are stored as attributes within the HTTP session. Since they must persist across multiple requests, they are stored in a session-associated memory space.

Lifecycle

  1. User visits the application: a new HTTP session is created
  2. Spring checks if a bean instance already exists for this session in the session scope registry
  3. If not, creates a new instance using reflection, stores it in the user’s HttpSession attributes, and returns the bean
  4. When the same user sends another request, Spring retrieves the existing session bean from HttpSession: no new object created
  5. The session bean persists until session timeout or explicit invalidation
  6. When the session ends, the session scope registry removes the bean: it becomes eligible for garbage collection

5. WebSocket Beans

This scope is useful for storing WebSocket-specific data, such as user authentication info, message history, or session-related state that should persist only while the WebSocket session is active.

Lifecycle

  1. Client establishes a WebSocket connection: Spring detects beans with @Scope("websocket")
  2. A new bean instance is created per WebSocket session
  3. The instance is stored in the WebSocket session context for that specific user
  4. Throughout the session, the same bean instance is reused for all messages exchanged
  5. The bean instance is not shared across different WebSocket connections: each client gets its own isolated instance
  6. When the WebSocket connection is closed, Spring automatically removes the bean from memory: eligible for garbage collection

Why Are Proxies Needed for Request, Session, and WebSocket Beans?

When injecting request, session, or WebSocket-scoped beans into a singleton bean, Spring doesn’t inject the actual instance but a proxy instead.

  • Why? Singleton beans are created once at startup, but request/session beans change per request or session. Without a proxy, the singleton bean would hold a stale reference.
  • How? The proxy dynamically resolves the correct instance at runtime, ensuring the singleton bean always gets the latest request/session-scoped object.

Summary

Choosing the right bean scope ensures optimal memory usage, better performance, and correct data isolation based on the application’s needs. Whether managing singleton services, per-request objects, or WebSocket sessions, understanding how Spring handles object creation and storage helps developers prevent memory leaks, unnecessary object creation, and unintended data sharing across users or requests.

ScopeStorageLifetimeBest For
SingletonHeap + Singleton CacheEntire applicationStateless services, repositories
PrototypeHeap onlyPer-request creationStateful, short-lived objects
RequestHTTP request attributesSingle HTTP requestRequest-specific processing
SessionHttpSession attributesSession lifetimeUser session data
WebSocketWebSocket session contextConnection lifetimeReal-time per-user state

Originally published on Medium · Javarevisited