java - 当 ChangeListener 输入为 lambda 时,JavaFX 中的 addListener 是否会被垃圾收集?
问题描述
我意识到我的项目使用了很多 JavaFXChangeListeners
来跟踪某些条件。
我很确定监听器在与 一起使用时不会被垃圾收集property.addListener(ChangeListener)
,但是如果我将监听器放在 lambda 形式而不是先声明它们,它们仍然不会被垃圾收集吗?
例子:
field.focusedProperty().addListener((obs, oldVal, newVal) -> {
// Do stuff
}
});
附带说明一下,当我关闭程序时,是否所有听众都被清除了,还是他们继续坚持?
解决方案
监听器会被垃圾收集吗?
只要在 observable 中注册,您向 observable 注册的侦听器就不会被垃圾收集。当然,假设有对可观察对象的强烈引用。这是因为 observable 保持对每个注册的监听器的强引用。事实上,如果您不小心,这可能是您的应用程序内存泄漏的原因。这就是为什么我们有:
弱听者
为了使您的应用程序更能抵抗内存泄漏,您可以使用WeakListener
. 为您提供了五个公共实现:
WeakInvalidationListener
WeakChangeListener
WeakListChangeListener
WeakSetChangeListener
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
此外,在以下情况下,使用弱侦听器可能比他们值得付出更多的努力:
- 您的应用程序是微不足道的或相对短暂的。
- 您的应用程序是相对静态的(即不会连续创建和丢弃您注册侦听器的对象)。
如果不确定,您始终可以从非弱路径开始,并且仅在您分析问题时才更改为弱侦听器。
事件处理程序
此处描述的所有内容都适用于EventHandler
和WeakEventHandler
。请注意,后者没有实现WeakListener
.
Lambda 表达式
使用 lambda 表达式来实现侦听器(或处理程序)会改变什么吗?与此上下文无关。lambda 表达式只是功能接口的实现。通过 lambda 表达式创建的实例与其他任何实例一样只是一个实例。
应用程序退出时会发生什么?
当所述进程退出时,分配给进程的所有内存都将释放回操作系统。这意味着所有对象都不再存在于内存中。
推荐阅读
- sql - 使用 PHPSpreadsheet 将 SQL 数据插入 Excel
- cocoa - 突出显示 NSPredicateEditor 中的选定行
- python - 将 pandas DataFrame 附加到带有固定标头的 csv
- python - 将文件上传到公共谷歌云存储桶
- c# - 请求类在 Razor 页面中不可用
- python - 熊猫将宽数据更改为长数据,后缀从负数到正数
- asp.net-core - 如何在 .NET Core 2.1 中使用 Azure AD 身份验证和 OpenIdConnect 交换 access_token 的授权代码?
- excel - 将值从用户窗体插入到 Excel 工作表
- python - 使用python添加和删除功能使两个滚动列表彼此相邻
- java - 如何计算从一个方法发送到另一个方法的总参数