Observable注册listener出现leak memory该如何处理

北战南征 提交于 2020-05-03 23:41:06

我们在JavaFX编程中,经常会将invalidation listener注册到Observerable接口的继承类的实例中,这是一种强引用“strong reference”,在生命周期短的程序中,这种问题引起的内存泄漏可惜忽略不计,因为当程序关闭后,泄露的内存都会释放掉。但是在生命周期长的程序中,这种注册方式会使得被观察实例始终会向注册的listener发送消息,即使这些listener再也不会使用。如下例,没有注销listener。

public class StrongListener {
    public static IntegerProperty counter = new SimpleIntegerProperty(100);
    public static void main(String[] args) {
        // Add a change listener to the property
        addStrongListener();
        // Change counter value. It will fire a change event.
        counter.set(300);
    }
    
    public static void addStrongListener() {
        ChangeListener<Number> listener = StrongListener::changed;
        counter.addListener(listener);
        // Change the counter value
        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);
    }
}

我们有以下几种方式来注销listener:

一:使用“void removeListener​(InvalidationListener listener)”注销listener,具体实例如下:

public class CleanupListener {
    
    public static void main(String[] args) {
        // Add a change listener to the property
        ChangeListener<Number> listener = CleanupListener::changed;
        counter.addListener(listener);
        
        // Change the counter value
        counter.set(200);
        
        // Remove the listener from property
        counter.removeListener(listener);
        
        // Will not fire change event as change listener has
        // already been removed.
        counter.set(300);
    }
    
    public static void changed(ObservableValue<? extends Number> prop,
                               Number oldValue,
                               Number newValue) {
        System.out.print("Counter changed: ");
        System.out.println("old = " + oldValue + ", new = " + newValue);
    }

    public static IntegerProperty counter = new SimpleIntegerProperty(100);
}

上例中,我们使用方法,将注册的listener移除,避免了内存泄漏。

如果我们在一个方法中将listener注册到Observerable中,但是没有地方适合写“removeListener方法”,那该如何避免内存泄漏呢?我们可以通过注册weak listener来手动注销。注意weak listener有“ WeakChangeListener”和“WeakInvalidationListener”两个,分别对应change、invalidation事件。具体使用方式如下:

ChangeListener<Number> cListener = create a change listener...
WeakChangeListener<Number> wListener = new WeakChangeListener(cListener);

将listener注册到weak listener,然后将weak listener注册到Observable中。

public class WeakListener {

    public static void main(String[] args) {
        // Add a weak change listener to the property
        addWeakListener();
        
        // It will fire a change event
        counter.set(300);
        
        // Try garbage collection
        System.gc();
        
        // Check if change listener got garbage collected
        System.out.println("Garbage collected: " +
                weakListener.wasGarbageCollected());
        
        // It will fire a change event
        counter.set(400);
        
        // You do not need a strong reference of the change listener
        changeListener = null;
        
        // Try garbage collection
        System.gc();
        
        // Check if the change listener got garbage collected
        System.out.println("Garbage collected: " +
                weakListener.wasGarbageCollected());
        
        // It will not fire a change event, if it was garbage collected
        counter.set(500);
    }

    /**
      @class      WeakListener
      @date       2020/5/3
      @author     qiaowei
      @version    1.0
      @brief      Property adds weak listener wrapping change listener
      @param      
      @return     
      @throws     
     */
    public static void addWeakListener() {
        // Keep a strong reference to the change listener
        changeListener = WeakListener::changed;
        
        // Wrap the change listener inside a weak change listener
        weakListener = new WeakChangeListener<>(changeListener);
        
        // Add weak change listener
        counter.addListener(weakListener);
//        counter.addListener(changeListener);
        
        // Change the value
        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);
    }
    
    public static IntegerProperty counter = new SimpleIntegerProperty(100);
    public static WeakChangeListener<Number> weakListener;
    public static ChangeListener<Number> changeListener;
}

运行结果:

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

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!