5

I am facing some problems with garbage collection while generating an application in java, where I use Stream.map to trim all the elements in the list. The instances of anonymous lambda class exist in the heap dump even though the instance of the enclosing class is 0 as shown in the snap of visual VM.

enter image description here

The LambdaTesting class:

class LambdaTesting {

    protected List<String> values;

    protected LambdaTesting(List<String> values) {
        this.values = values;
    }
    public List<String> modify() {      
        return this.values.stream().map(x -> x.trim()).collect(Collectors.toList());
    }
    public List<String> modifyLocal() {
        List<String> localValue = new ArrayList<>();
        localValue.add("Local FOO ");
        localValue.add("Local BAR ");
        return localValue.stream().map(x -> x.trim()).collect(Collectors.toList());     
   }
}

The method which creates the instance of LambdaTesting and invokes these methods:

public List<String> testMethods() {
    List<String> test = new ArrayList<>();      
    test.add("Global FOO  ");
    test.add("   GLOBAL BAR");  
    LambdaTesting lambdaTesting = new LambdaTesting(test);
    lambdaTesting.modifyLocal();
    lambdaTesting.modify();
}

The thread dump was taken after putting a debug point at the next line after testMethods is invoked.

Why are the references to Lambda still present in the heap dump?

Akhil
  • 78
  • 5
  • Doesn't that answer your question? https://stackoverflow.com/questions/1582209/java-garbage-collector-when-does-it-collect – Benjamin Eckardt Jun 02 '20 at 19:39
  • 2
    In this specific case, it’s rather [Does a lambda expression create an object on the heap every time it's executed?](https://stackoverflow.com/a/27524543/2711488) – Holger Jun 02 '20 at 19:50
  • 3
    Why wouldn't it save the lambda? It can save it once across all usages of the class and never instantiate the lambda again. – Louis Wasserman Jun 02 '20 at 20:01
  • @LouisWasserman Agreed. But say I have a large client application which has many child screens in it. Whenever I close a child screen I want all the instances of the child screens to be removed. In this case if the instances of lambdas associated with with child screen remains, wouldn't it cause a memory issue? – Akhil Jun 03 '20 at 04:29
  • @Holger Thank you for pointing it out. I have already seen this thread, but here I am concerned about the memory footprint. Its true the it creates a singleton but I was wondering why GC is not removing the instances of lambda, which I believe could result in potential memory leak. – Akhil Jun 03 '20 at 04:34
  • @BenjaminEckardt Than you for your response. I am afraid that it doesn't answer my question as the thread doesn't mention about handling cases in lambda. – Akhil Jun 03 '20 at 04:36

1 Answers1

5

As elaborated in Does a lambda expression create an object on the heap every time it's executed?, a non-capturing lambda expression will be remembered and reused, which implies that it is permanently associated with the code that created it. That’s not different to, e.g. string literals whose object representation stays in memory as long as the code containing the literal is alive.

This is an implementation detail. It doesn’t have to be that way, but the reference implementation and hence, all commonly used JREs do it that way.

A non-capturing lambda expression is a lambda expression that uses no (non-constant) variables of the surrounding context and does not use this, neither implicitly nor explicitly. So it bears no state, hence, consumes a tiny amount of memory. There is also no possibility to create a leak regarding other objects, as having references to other objects is what makes the difference between non-capturing and capturing lambda expressions and likely is the main reason why capturing lambda expressions are not remembered that way.

So the maximum number of such never-collected instances is equal to the total number of lambda expression in your application, which might be a few hundred or even thousands, but still small compared to the total number of objects the application will ever create. As explained in Function.identity() or t->t, putting a lambda expression into a factory method instead of repeating it in the source code, can reduce the number of instances. But given the rather small total number of objects, that’s rarely a concern. Compare with the number of the already mentioned string literals or the Class objects which already exist in the runtime…

Holger
  • 285,553
  • 42
  • 434
  • 765
  • Thank you for the detailed explanation. So I believe that, I don't have to worry about the instances of lambda expressions in the heap dump. – Akhil Jun 03 '20 at 09:22