【问题标题】:Java 8 lambda closure and GC [duplicate]Java 8 lambda 闭包和 GC [重复]
【发布时间】:2017-11-01 04:32:34
【问题描述】:

我对 java 8 的“闭包”有点困惑。据说它关闭了价值。 考虑下面的类。

public class SomeClassWithLargeMemoryFootprint {
     //some state
     private SomeObject someObj;
     //some more state

     public void doSomething(SomeAsyncHelper helper) {
         helper.doAsync( () -> {
                             //some super slow operation
                             int foo = someObj.whatever();
                             //some more stuff    
                       });
     }
}

.

//Let's assume SomeAsyncHelper.doAsync takes a VoidRunner that looks like below
interface VoidRunner {
    void apply();
}

问题是,当异步助手仍在工作时,是否可以对 SomeClassWithLargeMemoryFootprint 的实例进行 GC? 我很清楚“someObj”不能被 GC 处理,因为 doSomething() 中的 lambda 需要它。该州的其他地区呢?

此外,请考虑以下变体,其中我们调用包含类的成员方法:

public class SomeClassWithLargeMemoryFootprint {
     //some state
     private SomeObject someObj;
     //some more state

     public void doSomething(SomeAsyncHelper helper) {
         helper.doAsync( () -> {
                //do something
                memberMethod();
                //do something else
                });
     }

     private void memberMethod() {
         //do something
     }

}

现在呢? “助手”如何知道如何执行“memberMethod”?它是否获得了对 SomeClassWithLargeMemoryFootprint 实例的引用? GC 序列是什么?

【问题讨论】:

标签: java lambda garbage-collection


【解决方案1】:

当异步助手仍在工作时,是否可以对 SomeClassWithLargeMemoryFootprint 的实例进行 GC?

没有。 VoidRunner 实例对其封闭的 SomeClassWithLargeMemoryFootprint 对象具有强引用,并且它本身被异步任务执行器以某种方式引用。所以它不能被 GCed。

该州的其他地区呢?

状态的其余部分被 SomeClassWithLargeMemoryFootprint 的实例引用,所以不能被 GC。

'helper'是如何知道如何执行“memberMethod”的

与第一个示例中它知道如何访问someObj(即this.someObj)的方式相同:它引用了其封闭的 SomeClassWithLargeMemoryFootprint 对象(即this)。

【讨论】:

  • 酷..谢谢!匿名类持有对封闭类的引用这一事实说明了这一点。
  • 一个后续问题:当我不访问 lambda 中的任何封闭类的成员时,有没有办法打破对封闭类的强引用?我的意思是一种简洁的方式,与使用 lambda 的便利性不太不同。不是实现 lambda 接口的具体类。
  • @Saivivekh Swaminathan:当您不访问周围实例的成员时,lambda 表达式将不会捕获对周围实例的引用。在这种情况下,没有必要“打破强引用”。在您的第一个变体中,您仅在 someObj 上调用方法,您可以通过首先将目标对象读入局部变量 SomeObject localVar = this.someObj; 并仅使用 lambda 中的局部变量来避免捕获 thishelper.doAsync( () -> { … int foo = localVar.whatever(); … }); 仅通过localVar 捕获SomeObject 实例
  • @Holger:感谢您的回复。这意味着无论谁说 lambda 只是内联匿名类的语法糖,都是错误的,对吧?根据stackoverflow.com/questions/5054360/…,匿名内联类显然总是获得对封闭类的引用。
猜你喜欢
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-21
  • 1970-01-01
  • 1970-01-01
  • 2018-01-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多