簡體   English   中英

為什么這個弱聽者不會被垃圾收集?

[英]Why is this weak listener not garbage collected?

這是Kishori Sharan的《 Learn JavaFX 8》一書中的一個示例:

package sample;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.beans.value.WeakChangeListener;

public class WeakListener {
    public static IntegerProperty counter = new SimpleIntegerProperty(100);
    public static WeakChangeListener<Number> weakListener;
    public static ChangeListener<Number> changeListener;

    public static void main(String[] args) {
        // Add a weak change listener to the property
        addWeakListener();
        counter.set(300);
        System.gc();
        System.out.println("Garbage collected: " +
                weakListener.wasGarbageCollected());
        counter.set(400);
        changeListener = null;
        System.gc();
        System.out.println("Garbage collected: " +
                weakListener.wasGarbageCollected());
        counter.set(500);
    }

    public static void addWeakListener() {
        changeListener = WeakListener::changed;
        weakListener = new WeakChangeListener<>(changeListener);
        counter.addListener(weakListener);
        counter.set(200);
    }

    public static void changed(ObservableValue<? extends Number> prop,
                               Number oldValue,
                               Number newValue) {
        System.out.print("Counter changed: ");
        System.out.println("old = " + oldValue + ", new = " + newValue);
    }
}

在將強偵聽器設置為null之后,應該對弱偵聽器進行GC:

在此處輸入圖片說明

但結果與預期不同:

Counter changed: old = 100, new = 200
Counter changed: old = 200, new = 300
Garbage collected: false
Counter changed: old = 300, new = 400
Garbage collected: false
Counter changed: old = 400, new = 500

我在OSX優勝美地上使用jdk 1.8_u51。

恐怕這篇文章是錯誤的-這是更正的句子:

將其設置為null ,然后再次調用垃圾回收之后,更改偵聽器可能會被垃圾回收。

本質上,Java中沒有System.gc();合同System.gc(); 請參閱此處的措辭,其狀態(我強調):

調用gc方法表明 ,Java虛擬機將花費更多精力來回收未使用的對象,以使它們當前占用的內存可用於快速重用。 當控件從方法調用返回時,Java虛擬機將盡最大努力從所有丟棄的對象中回收空間。

那里什么也沒有說它實際上會收集任何垃圾。

一個簡單但令人失望的答案:System.gc()不會強制進行垃圾回收。 它所做的只是告訴VM現在是收集垃圾的好時機。 VM現在不必運行垃圾收集。

如果VM例如認為有足夠的剩余內存,那么它可能那時不運行垃圾回收。

因此,如果您真的想測試垃圾回收,請提高內存使用率並在更長的時間內多次運行System.gc()。 這樣,您可能會增加收集收聽者的機會。

這里同樣的問題。

我發現只是從方法引用更改了ChangeListener的創建:

changeListener = WeakListener::changed;

到一個普通的匿名老班

changeListener = new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                System.out.print("Counter changed: ");
                System.out.println("old = " + oldValue + ", new = " + newValue);
            }
        };

確實輸出得很好:

Counter changed: old = 100, new = 200
Counter changed: old = 200, new = 300
Garbage collected: false
Counter changed: old = 300, new = 400
Garbage collected: true

哇! 這是與Lambda相關的錯誤嗎? 在JDK8U60中使用Win7 X64

您將在靜態變量weakListener中保留對WeakChangeListener的引用。

僅當對象沒有任何引用時才對其進行垃圾回收。

當您使changeListener無效時,它將保留對weakListener的內部引用,但是只要至少有一個引用,該對象將保留在內存中。

編輯:

我不知道弱引用如何在Java上工作。 如果像我一樣,某人不了解它們,那么https://weblogs.java.net/blog/2006/05/04/understanding-weak-references是不錯的閱讀方法。

暫無
暫無

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

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