Fundamentals 7 min read

Avoiding Memory Leaks with Java Double‑Brace Initialization and Anonymous Inner Classes

This article explains Java's double‑brace initialization trick, shows how it creates anonymous inner classes, demonstrates the resulting memory‑leak and OOM risks, especially with non‑static inner classes, and provides guidelines such as using static inner classes or weak references to avoid these problems.

Cognitive Technology Team
Cognitive Technology Team
Cognitive Technology Team
Avoiding Memory Leaks with Java Double‑Brace Initialization and Anonymous Inner Classes

The article introduces the double‑brace initialization technique in Java, which is often used to simplify object creation such as building SQL statements with MyBatis or initializing collections.

Official MyBatis documentation shows an example using new SQL() {{ SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME"); SELECT("P.LAST_NAME, P.CREATED_ON, P.UPDATED_ON"); FROM("PERSON P"); FROM("ACCOUNT A"); INNER_JOIN("DEPARTMENT D on D.ID = P.DEPARTMENT_ID"); INNER_JOIN("COMPANY C on D.COMPANY_ID = C.ID"); WHERE("P.ID = A.ID"); WHERE("P.FIRST_NAME like ?"); OR(); WHERE("P.LAST_NAME like ?"); GROUP_BY("P.ID"); HAVING("P.LAST_NAME like ?"); OR(); HAVING("P.FIRST_NAME like ?"); ORDER_BY("P.ID"); ORDER_BY("P.FULL_NAME"); }}.toString(); and a similar snippet for a DELETE statement.

Beyond MyBatis, the same double‑brace syntax is often used to initialize maps, for example:

Map names = new HashMap<>(); names.put(1, "崔"); names.put(2, "认"); names.put(3, "知");

Using double‑brace initialization, the code becomes:

Map names = new HashMap<>() {{ put(1, "崔"); put(2, "认"); put(3, "知"); }};

The first pair of braces creates an anonymous subclass of HashMap , and the second pair is an instance initializer block. This hidden anonymous class generation can be seen when decompiling the compiled class files, which produce classes such as Demo$1 and Demo$2 .

Decompiling Demo$1 shows it extends java.util.HashMap and contains a synthetic field referencing the outer class ( Demo.this$0 ). Because the anonymous inner class holds an implicit reference to its enclosing instance, if the inner class outlives the outer class, the outer class cannot be garbage‑collected, leading to a memory leak.

An example that triggers this leak:

private Map map() { return new HashMap<>() {{ put(1, "认知科技技术团队"); put(2, "链接"); put(3, "....."); }}; }

Decompiling the generated class reveals the hidden reference:

class com.renzhikeji.demo.Demo$1 extends java.util.HashMap { final com.renzhikeji.demo.Demo this$0; Demo$1(com.renzhikeji.demo.Demo); }

When many such anonymous classes are created at runtime, the JVM may load a large number of classes, consume significant memory, and even trigger Out‑Of‑Memory errors, especially on Android where non‑static anonymous inner classes are common.

To avoid these problems, the article recommends:

Using static inner classes instead of anonymous non‑static ones, because static inner classes do not retain a reference to the outer instance.

If access to the outer class is needed, using a weak reference to prevent strong coupling.

In summary, while double‑brace initialization offers concise syntax, it implicitly creates anonymous inner classes that can cause memory‑leak and OOM issues; developers should prefer static inner classes or other initialization patterns to keep Java applications memory‑safe.

Javabest practicesmemory-leakoomAnonymous Inner ClassDouble Brace Initialization
Cognitive Technology Team
Written by

Cognitive Technology Team

Cognitive Technology Team regularly delivers the latest IT news, original content, programming tutorials and experience sharing, with daily perks awaiting you.

0 followers
Reader feedback

How this landed with the community

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