Akh*_*hil 5 java lambda garbage-collection java-8 java-stream
我在用 java 生成应用程序时遇到了一些垃圾收集问题,我使用 Stream.map 修剪列表中的所有元素。匿名 lambda 类的实例存在于堆转储中,即使封闭类的实例为 0,如可视化 VM 的快照所示。
LambdaTesting 类:
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());
}
}
Run Code Online (Sandbox Code Playgroud)
创建 LambdaTesting 实例并调用这些方法的方法:
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();
}
Run Code Online (Sandbox Code Playgroud)
线程转储是在调用testMethods后在下一行放置调试点后进行的。
为什么对 Lambda 的引用仍然存在于堆转储中?
正如lambda 表达式每次执行时都会在堆上创建一个对象吗?,非捕获 lambda 表达式将被记住并重用,这意味着它与创建它的代码永久关联。\xe2\x80\x99 与字符串文字没有什么不同,只要包含文字的代码存在,其对象表示就保留在内存中。
\n\n这是一个实现细节。\xe2\x80\x99 不一定是这样,但参考实现以及所有常用的 JRE 都这样做。
\n\n非捕获 lambda 表达式是不使用周围上下文的(非常量)变量并且不使用this
隐式或显式使用 的 lambda 表达式。所以它没有状态,因此消耗很少的内存。也不可能创建关于其他对象的泄漏,因为对其他对象的引用是非捕获和捕获 lambda 表达式之间的区别,并且可能是捕获 lambda 表达式不以这种方式被记住的主要原因。
因此,此类从未收集的实例的最大数量等于应用程序中 lambda 表达式的总数,可能是几百甚至数千,但与应用程序将创建的对象总数相比仍然很小。正如Function.identity() 或 t->t中所解释的,将 lambda 表达式放入工厂方法中而不是在源代码中重复它,可以减少实例的数量。但考虑到对象总数相当小,\xe2\x80\x99s 很少是一个问题。与已经提到的字符串文字的数量或Class
与已经提到的字符串文字或运行时\xe2\x80\xa6中已存在的对象
归档时间: |
|
查看次数: |
363 次 |
最近记录: |