首页 > 解决方案 > 当 ChangeListener 输入为 lambda 时,JavaFX 中的 addListener 是否会被垃圾收集?

问题描述

我意识到我的项目使用了很多 JavaFXChangeListeners来跟踪某些条件。

我很确定监听器在与 一起使用时不会被垃圾收集property.addListener(ChangeListener),但是如果我将监听器放在 lambda 形式而不是先声明它们,它们仍然不会被垃圾收集吗?

例子:

        field.focusedProperty().addListener((obs, oldVal, newVal) -> {
          // Do stuff
          }
        });

附带说明一下,当我关闭程序时,是否所有听众都被清除了,还是他们继续坚持?

标签: javajavafxmemorygarbage-collectionlistener

解决方案


监听器会被垃圾收集吗?

只要在 observable 中注册,您向 observable 注册的侦听器就不会被垃圾收集。当然,假设有对可观察对象的强烈引用。这是因为 observable 保持对每个注册的监听器的强引用。事实上,如果您不小心,这可能是您的应用程序内存泄漏的原因。这就是为什么我们有:

弱听者

为了使您的应用程序更能抵抗内存泄漏,您可以使用WeakListener. 为您提供了五个公共实现:

  1. WeakInvalidationListener
  2. WeakChangeListener
  3. WeakListChangeListener
  4. WeakSetChangeListener
  5. WeakMapChangeListener

这些实现包装了它们对应的监听器并将其保存在一个WeakReference. 这样,observable 只对弱侦听器有强引用,而不是“真正的”侦听器。这就是为什么你必须自己保持对“真实”监听器的强烈引用,只要它需要,否则它会很快被垃圾收集。

例子

这是使用弱侦听器的示例:

import javafx.beans.value.ChangeListener;
import javafx.beans.value.WeakChangeListener;
import javafx.scene.Node;

public class Foo {
  
  // strong reference to "real" listener
  private final ChangeListener<Boolean> focusListener =
      (obs, oldVal, newVal) -> {
        // do something...
      };

  private final Node node;

  public Foo(Node node) {
    this.node = node;
    node.focusedProperty().addListener(new WeakChangeListener<>(focusListener));
  }
}

如果您需要能够随意删除弱侦听器,那么您还需要保留对它的引用。

何时使用弱侦听器

当您不能保证不再需要时删除侦听器时,您应该使用弱侦听器。如果侦听器捕获对其他对象的引用(例如上面示例中的实例),这一点尤其重要Foo

如果保证可观察对象和侦听器在相对同时被垃圾收集,请不要使用弱侦听器。例如,如果Foo有一个属性并向所述属性本身添加一个监听器(例如),那么当实例被this.someProperty().addListener((...) -> {...})垃圾收集时,该属性以及监听器将被垃圾收集。Foo

此外,在以下情况下,使用弱侦听器可能比他们值得付出更多的努力:

  • 您的应用程序是微不足道的或相对短暂的。
  • 您的应用程序是相对静态的(即不会连续创建和丢弃您注册侦听器的对象)。

如果不确定,您始终可以从非弱路径开始,并且仅在您分析问题时才更改为弱侦听器。

事件处理程序

此处描述的所有内容都适用于EventHandlerWeakEventHandler。请注意,后者没有实现WeakListener.

Lambda 表达式

使用 lambda 表达式来实现侦听器(或处理程序)会改变什么吗?与此上下文无关。lambda 表达式只是功能接口的实现。通过 lambda 表达式创建的实例与其他任何实例一样只是一个实例。

应用程序退出时会发生什么?

当所述进程退出时,分配给进程的所有内存都将释放回操作系统。这意味着所有对象都不再存在于内存中。


推荐阅读