Why a Simple HashMap Bug Caused Massive Memory Leaks in High‑Concurrency Java Services

An overconfident architect introduced a high‑traffic monitoring feature using ConcurrentHashMap without proper equals/hashCode overrides, causing millions of duplicate keys, memory leaks, and crashes; the team debated synchronized versus putIfAbsent solutions, ultimately fixing the bug and highlighting essential concurrency and code‑review practices for Java back‑end development.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Why a Simple HashMap Bug Caused Massive Memory Leaks in High‑Concurrency Java Services

A new architect with a BAT background joined the department, boasting massive high‑concurrency experience and immediately took on the most concurrent task: collecting the average response time and total request count of all interfaces.

He implemented the monitoring logic with a ConcurrentHashMap, storing a monitor key and value for every request, and claimed that no comments were needed.

Because the key class did not override equals() and hashCode(), each request generated a distinct key object, leading to millions of duplicate entries in the heap and eventually an OutOfMemoryError. Monitor$MonitorKey@15aeb7ab The team used jmap and Eclipse MAT to analyze the heap and found that MonitorKey and MonitorValue objects filled the memory.

A quick fix was attempted by adding a synchronized keyword to the visit method, but this introduced a coarse‑grained lock.

public synchronized void visit(String url, String desc, long timeCost)

A more efficient solution was proposed: use ConcurrentHashMap.putIfAbsent to create the value atomically and then update counters.

MonitorKey key = new MonitorKey(url, desc);
MonitorValue value = monitors.putIfAbsent(key, new MonitorValue());
value.count.getAndIncrement();
value.totalTime.getAndAdd(timeCost);
value.avgTime = value.totalTime.get() / value.count.get();

The discussion escalated, with the technical director arguing that a simple synchronized method is safer for production, while others advocated the lock‑free approach.

Ultimately the bug was resolved by correctly overriding equals() and hashCode() for the monitor key and by adopting the putIfAbsent pattern, eliminating the memory leak and stabilizing the service.

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.

SynchronizationConcurrentHashMapMemoryLeakCodeReview
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.