簡體   English   中英

Java lambdas 堆轉儲 - lambda 的實例未收集垃圾

[英]Java lambdas heap dump - Instance of lambda not getting garbage collected

在 java 中生成應用程序時,我遇到了一些垃圾收集問題,我使用 Stream.map 修剪列表中的所有元素。 匿名 lambda class 的實例存在於堆轉儲中,即使封閉的 class 的實例為 0,如可視 VM 的快照所示。

在此處輸入圖像描述

朗達測試 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());     
   }
}

創建 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();
}

在調用testMethods后在下一行放置一個調試點后進行線程轉儲。

為什么堆轉儲中仍然存在對 Lambda 的引用?

正如lambda 表達式是否在每次執行時都會在堆上創建一個 object 中所述? ,一個非捕獲的 lambda 表達式將被記住並重用,這意味着它與創建它的代碼永久關聯。 這與例如字符串文字的 object 表示保持在 memory 中沒有什么不同,只要包含文字的代碼是活動的。

這是一個實現細節。 不一定要那樣,但是參考實現以及所有常用的 JRE 都是那樣做的。

非捕獲 lambda 表達式是 lambda 表達式,它不使用周圍上下文的(非常量)變量並且不使用this ,既不隱式也不顯式。 所以它沒有 state,因此消耗了少量的 memory。 也不可能創建有關其他對象的泄漏,因為對其他對象的引用是非捕獲和捕獲 lambda 表達式之間的區別的原因,並且可能是捕獲 lambda 表達式不以這種方式記住的主要原因。

因此,此類從未收集的實例的最大數量等於應用程序中 lambda 表達式的總數,可能是幾百甚至幾千個,但與應用程序將創建的對象總數相比仍然很小。 Function.identity() 或 t->t中所述,將 lambda 表達式放入工廠方法中,而不是在源代碼中重復它,可以減少實例的數量。 但鑒於對象的總數相當少,這幾乎不是問題。 與已經提到的字符串文字或運行時中已經存在的Class對象的數量進行比較......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM