How MemorySafeLBQ Prevents OOM in Java Thread Pools – A Deep Dive

This article explores the design and implementation of MemoryLimitedLBQ and MemorySafeLBQ, two custom LinkedBlockingQueue variants that limit memory usage to avoid Out‑Of‑Memory errors in Java thread pools, comparing their mechanisms, instrumentation dependencies, and practical usage in open‑source projects.

Java Backend Technology
Java Backend Technology
Java Backend Technology
How MemorySafeLBQ Prevents OOM in Java Thread Pools – A Deep Dive

MemorySafeLBQ

When browsing an open‑source PR on Apache Dubbo, I discovered a queue named MemorySafeLBQ that promises to be memory‑safe, sparking curiosity about its implementation.

The author explains why FixedThreadPool and SingleThreadPool are discouraged: their unbounded LinkedBlockingQueue can grow to Integer.MAX_VALUE, leading to OOM.

To mitigate this, two custom queues were introduced:

MemoryLimitedLBQ – limits the total memory a queue can occupy by tracking each element’s size using Instrumentation.getObjectSize.

MemorySafeLBQ – limits queue insertion based on the JVM’s remaining free memory, using ManagementFactory.getMemoryMXBean instead of instrumentation.

MemoryLimitedLBQ

This queue extends LinkedBlockingQueue and adds a memoryLimiter that maintains memoryLimit, a LongAdder memory for current usage, and several locks. The put method calls memoryLimiter.acquireInterruptibly, which checks the object’s size and blocks if adding it would exceed memoryLimit.

A bug was identified where the local variable sum was used instead of the up‑to‑date memory.sum(), causing a potential dead‑loop. The fix replaces sum with memory.sum().

MemorySafeLBQ

Unlike its predecessor, MemorySafeLBQ does not rely on Instrumentation. It defines maxFreeMemory (default 256 MiB) and checks the JVM’s free memory via MemoryMXBean. If the remaining memory falls below the threshold, insertion is rejected.

The queue overrides put and offer to call hasRemainedMemory before delegating to the superclass, simplifying usage.

Comparison and Usage

Both queues can be copied into any project without framework dependencies. MemoryLimitedLBQ offers fine‑grained control per element but requires instrumentation; MemorySafeLBQ provides a simpler, JVM‑wide safeguard without extra agents.

Examples and test cases are linked in the original PRs, and the author suggests extending the concept to other data structures like local caches or dynamically adjusting queue parameters.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

InstrumentationConcurrencyopen-sourcememory-managementlinkedblockingqueuethread-pool
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.