Java Lambda and the Garbage Collector [part 1]

Tan Bui
3 min readJun 27, 2020

Lambda in the memory

Is lambda just like an (anonymous) inner class?

NO — when talking about closures. This is a great article about Lambda limitations and closure, including a comparison to Javascript.

YES — when talking about memory allocation — in case that inner class is declared properly. This is what I’m going to discuss further in this article.

Stateless — having no reference to the enclosing scope

Let’s check Example 1:

Example 1. Stateless lambda vs inner class

Note: I avoid using Method Reference or any too-short syntax so we can see the lambda expression easier. 😳

Even lambdaPrinter and myPrinter are used similarly, they’re stored differently. myPrinter is a normal local variable which refers to aPrinter instance in Heap. When myPrinter = null or main() is finished, that instance is garbage-collected as usual.

However, lambdaPrinterdoes not. Since this lambda has no reference to its enclosing scope, it is stored as a static variable which is NOT a target of Garbage Collector. Let’s call it a stateless lambda.

Here’s how they look in the Heap:

Fig 1. Lambda vs instance variable in Heap

So, if myPrinter is static, would it be treated like lambdaPrinter ? YES. Or actually, we only need to define Printer as a static class to tell JVM that it has no reference to the enclosing instance. In this case, the Heap looks like:

Fig 2. Lambda vs static instance variable in Heap

And this is the proper way to define a stateless inner class.

Stateful lambda

In contrast to stateless lambdas, stateful lambdas call external local variables (variables which are defined outside of the lambda’s body block) or access to a field or method of its enclosing instance.

In this case, a lambda closure is created with references to the external local instances and the enclosing instance. These instances are passed into the lambda function — or I can call it as lambda instance now since it could be garbage-collected just like a normal instance of a class.

In Example 2, lambdaPrinter accesses to myStr local variable and this instance via this.superPrint.

Example 2. Stateful lambda vs inner class

And the Heap looks like:

Fig 3. Stateful lambda instance

You can see two references of LambdaLifecycle and String instances are COPIED into to lambdaPrinter closure as two arguments. In case the local variables are primitive, their values are copied. Because of that, those local variables are not allowed to be changed or re-assigned so the lambda can find those values/references when executing later. For instance:

Consumer<String> lambdaPrinter = str -> {
this.superPrint(myStr); // compile error
myStr = "foo"; // because of this
enclosingField = "bar";
};

That’s why Variable used in lambda expression should be final or effectively final.

To sum up, a lambda function is stateful when it accesses references outside its body (variables, enclosing scope). Stateful lambda can be collected by GC. Otherwise, it’s stateless — just like a static inner class.

In Java Lambda and the Garbage Collector [part 2], I demonstrate how to test if GC correctly collects lambdas.

--

--

Tan Bui

Software Engineer @Smartly.io, phototaker, naturelover.