Anonymous Inner Classes vs Lambda Expressions: Memory Leak Risks in Java
This article examines how anonymous inner classes and lambda expressions differ in their handling of outer class references, analyzes compiled bytecode to reveal potential memory leak risks, and demonstrates how explicit references affect lambda behavior in Java Android development.
Background
Anonymous inner classes hold a reference to their enclosing class, which can cause memory leaks; the article investigates whether lambda expressions exhibit the same risk.
Anonymous Inner Class vs Lambda Expression
A sample class TestInner is created with two methods: test (containing a lambda) and test1 (containing an anonymous inner class). The source code is:
public class TestInner {
public void test(){
new Thread(()->{
Log.i("测试","dddd");
}).start();
}
public void test1(){
new Thread(new Runnable() {
@Override
public void run() {
Log.i("测试","dddd1");
}
}).start();
}
}After compiling to an APK, the bytecode for test1 (anonymous inner class) shows the creation of TestInner$1 and an implicit reference to the outer TestInner instance.
.method public test1()V
.registers 3
.line 14
new-instance v0, Ljava/lang/Thread;
new-instance v1, Lcom/example/jnihelper/TestInner$1;
invoke-direct {v1, p0}, Lcom/example/jnihelper/TestInner$1;->
(Lcom/example/jnihelper/TestInner;)V
invoke-direct {v0, v1}, Ljava/lang/Thread;->
(Ljava/lang/Runnable;)V
.line 19
invoke-virtual {v0}, Ljava/lang/Thread;->start()V
.line 20
return-void
.end methodThe constructor of TestInner$1 stores the outer instance in a field this$0 , confirming the reference.
For the lambda version, the compiled bytecode shows the creation of a synthetic class TestInner$$ExternalSyntheticLambda0 that does not hold the outer reference when the lambda does not access any outer members:
.method static synthetic Lambda表达式()V
.registers 2
.line 9
const-string v0, "\u6d4b\u8bd5"
const-string v1, "dddd"
invoke-static {v0, v1}, Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
.line 10
return-void
.end method
.method public test()V
.registers 3
.line 8
new-instance v0, Ljava/lang/Thread;
sget-object v1, Lcom/example/jnihelper/TestInner$$ExternalSyntheticLambda0;->INSTANCE:Lcom/example/jnihelper/TestInner$$ExternalSyntheticLambda0;
invoke-direct {v0, v1}, Ljava/lang/Thread;->
(Ljava/lang/Runnable;)V
.line 10
invoke-virtual {v0}, Ljava/lang/Thread;->start()V
.line 11
return-void
.end methodThe synthetic lambda class implements Runnable but does not store an outer instance, indicating no memory‑leak risk.
Explicit Outer Reference in Lambda
When the lambda explicitly accesses a field of the outer class, the compiler generates a synthetic lambda class that captures the outer instance:
public class TestInner {
private String helloInner = "helloIIIII";
public void test(){
new Thread(() -> {
Log.i("测试", "dddd");
Log.i("测试", TestInner.this.helloInner); // explicit reference
}).start();
}
}The resulting bytecode shows the synthetic lambda constructor receiving the outer TestInner as a parameter and storing it in a field f$0 :
.method public synthetic constructor
(Lcom/example/jnihelper/TestInner;)V
.registers 2
invoke-direct {p0}, Ljava/lang/Object;->
()V
iput-object p1, p0, Lcom/example/jnihelper/TestInner$$ExternalSyntheticLambda0;->f$0:Lcom/example/jnihelper/TestInner;
return-void
.end method
.method public final run()V
.registers 2
iget-object v0, p0, Lcom/example/jnihelper/TestInner$$ExternalSyntheticLambda0;->f$0:Lcom/example/jnihelper/TestInner;
invoke-virtual {v0}, Lcom/example/jnihelper/TestInner;->lambda$test$0$com-example-jnihelper-TestInner()V
return-void
.end methodThus, a lambda only holds the outer reference when it actually accesses outer members.
Conclusion
Anonymous inner classes always retain a reference to their enclosing class, posing a memory‑leak risk. Lambda expressions do not capture the outer instance unless the lambda body explicitly references it, making them a safer alternative for avoiding leaks in Android development.
Java Architect Essentials
Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.