当ChangeListener被类型化为lambda时,JavaFX中的addListener是否会被垃圾收集?

当ChangeListener被类型化为lambda时,JavaFX中的addListener是否会被垃圾收集?,java,javafx,memory,garbage-collection,listener,Java,Javafx,Memory,Garbage Collection,Listener,我意识到我的项目使用了很多JavaFXChangeListener来跟踪某些条件 我非常确定,当与property.addListenerChangeListener一起使用时,侦听器不会被垃圾收集,但是如果我将侦听器放在lambda形式中,而不是首先声明它们,它们还会不会被垃圾收集吗 例如: field.focusedProperty().addListener((obs, oldVal, newVal) -> { // Do stuff

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

我非常确定,当与property.addListenerChangeListener一起使用时,侦听器不会被垃圾收集,但是如果我将侦听器放在lambda形式中,而不是首先声明它们,它们还会不会被垃圾收集吗

例如:

        field.focusedProperty().addListener((obs, oldVal, newVal) -> {
          // Do stuff
          }
        });
另一方面,当我关闭程序时,是否所有侦听器都被清除,或者它们是否继续存在?

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

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

WeakInvalidationListener 弱更改侦听器 软弱的听众 懦夫 薄弱环节 这些实现将相应的侦听器包装起来,并将其保存在WeakReference中。这样,可观察的对象只对弱的听者有很强的引用,而不是真正的听者。这就是为什么你必须在需要的时候保持对真实听众的强烈引用,否则它会很快被垃圾收集

实例 下面是一个使用弱侦听器的示例:

导入javafx.beans.value.ChangeListener; 导入javafx.beans.value.WeakChangeListener; 导入javafx.scene.Node; 公开课Foo{ //对真实听众的强引用 私有最终ChangeListener焦点Listener= obs、旧值、新值->{ //做点什么。。。 }; 私有最终节点; 公共节点{ this.node=节点; node.focusedProperty.addListenernew-WeakChangeListenerfocusListener; } } 如果您需要能够随意删除弱侦听器,那么您还需要保留对它的引用

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

如果可以保证可观测对象和侦听器在相对相同的时间被垃圾收集,那么不要麻烦使用弱侦听器。例如,如果Foo有一个属性,并将侦听器添加到所述属性本身,例如this.someProperty.addListener…->{…}然后当对Foo实例进行垃圾收集时,将对属性以及侦听器进行垃圾收集

此外,如果出现以下情况,则使用弱侦听器可能会付出比其价值更大的努力:

您的应用程序很琐碎或寿命相对较短。 您的应用程序是相对静态的,即不连续创建和丢弃您注册侦听器的对象。 如果不确定,您可以始终选择非弱路径开始,并且只有在您分析问题时才更改为弱侦听器

事件句柄 这里描述的一切对于EventHandler和WeakEventHandler都是一样的。请注意,后者没有实现WeakListener

表达式
使用lambda表达式实现侦听器或处理程序会改变什么吗?与此背景无关。lambda表达式只是函数接口的实现。通过lambda表达式创建的实例与其他任何实例一样

当应用程序退出时会发生什么? 当所述进程退出时,分配给该进程的所有内存被释放回操作系统。这意味着所有对象都不再存在于内存中。

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

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

WeakInvalidationListener 弱更改侦听器 软弱的听众 懦夫 薄弱环节 这些实现将相应的侦听器包装起来,并将其保存在WeakReference中。这样,可观察的对象只对弱的听者有很强的引用,而不是真正的听者。这就是为什么你必须在需要的时候保持对真实听众的强烈引用,其他人 明智的做法是垃圾收集得太快

实例 下面是一个使用弱侦听器的示例:

导入javafx.beans.value.ChangeListener; 导入javafx.beans.value.WeakChangeListener; 导入javafx.scene.Node; 公开课Foo{ //对真实听众的强引用 私有最终ChangeListener焦点Listener= obs、旧值、新值->{ //做点什么。。。 }; 私有最终节点; 公共节点{ this.node=节点; node.focusedProperty.addListenernew-WeakChangeListenerfocusListener; } } 如果您需要能够随意删除弱侦听器,那么您还需要保留对它的引用

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

如果可以保证可观测对象和侦听器在相对相同的时间被垃圾收集,那么不要麻烦使用弱侦听器。例如,如果Foo有一个属性,并将侦听器添加到所述属性本身,例如this.someProperty.addListener…->{…}然后当对Foo实例进行垃圾收集时,将对属性以及侦听器进行垃圾收集

此外,如果出现以下情况,则使用弱侦听器可能会付出比其价值更大的努力:

您的应用程序很琐碎或寿命相对较短。 您的应用程序是相对静态的,即不连续创建和丢弃您注册侦听器的对象。 如果不确定,您可以始终选择非弱路径开始,并且只有在您分析问题时才更改为弱侦听器

事件句柄 这里描述的一切对于EventHandler和WeakEventHandler都是一样的。请注意,后者没有实现WeakListener

表达式
使用lambda表达式实现侦听器或处理程序会改变什么吗?与此背景无关。lambda表达式只是函数接口的实现。通过lambda表达式创建的实例与其他任何实例一样

当应用程序退出时会发生什么?
当所述进程退出时,分配给该进程的所有内存被释放回操作系统。这意味着所有对象都不再存在于内存中。

谢谢!作为后续,表示ChangeListener的lambda仍然算作强引用吗?我尝试使用WeakListener,但在使用它之前,我不知道如何防止它被垃圾收集。lambda表达式只是一个函数接口的实现。您可以像其他任何实例一样获得该接口的一个实例。在程序打开的整个过程中,有许多常规而非弱的侦听器可以保持吗?我需要他们在每次数据更改时不断更新GUI的各个部分。在退出程序之前,我是否需要单独存储它们并将其删除?我编辑了我的答案。这有帮助吗?垃圾收集的工作原理在理论上看似简单,但实现却很复杂。基本上,有一个由应用程序创建的对象引用图。此图有一个或多个根,例如线程对象。垃圾收集器遍历图形,它无法到达的每个对象都有资格进行垃圾收集。因此,当且仅当侦听器没有其他强引用时,侦听器将与可观察对象一起被垃圾收集。这是在不麻烦的情况下。。。以上段落。谢谢!作为后续,表示ChangeListener的lambda仍然算作强引用吗?我尝试使用WeakListener,但在使用它之前,我不知道如何防止它被垃圾收集。lambda表达式只是一个函数接口的实现。您可以像其他任何实例一样获得该接口的一个实例。在程序打开的整个过程中,有许多常规而非弱的侦听器可以保持吗?我需要他们在每次数据更改时不断更新GUI的各个部分。在退出程序之前,我是否需要单独存储它们并将其删除?我编辑了我的答案。这有帮助吗?垃圾收集的工作原理在理论上看似简单,但实现却很复杂。基本上,有一个由应用程序创建的对象引用图。此图有一个或多个根,例如线程对象。垃圾收集器遍历图形,它无法到达的每个对象都有资格进行垃圾收集。因此,当且仅当侦听器没有其他强引用时,侦听器将与可观察对象一起被垃圾收集。这是在不麻烦的情况下。。。上文第段。