隐藏阶段时的JavaFX 8内存泄漏

Posted

技术标签:

【中文标题】隐藏阶段时的JavaFX 8内存泄漏【英文标题】:JavaFX 8 Memory leak when Hiding Stage 【发布时间】:2014-08-14 23:14:50 【问题描述】:

我有一个 JavaFX 应用程序,当按下 X 按钮时,它会最小化到托盘。我一直在通过 VisualVM 监控应用程序的内存趋势。

奇怪的是,当应用程序打开或最小化到任务栏时,内存总是被 GC 回收到最初使用的内存。但是,当它最小化到托盘时(stage.hide()systemTray.show()),内存会被 GC,但呈上升趋势(泄漏)。

在 VisualVM 中,Old Gen 空间不断增加,一段时间后达到最大值,应用程序将无响应,CPU 峰值达到 80%。

我注意到如果我在应用程序上双击托盘图标等stage.show(),GC 将清除一切恢复正常。但是,如果长时间放置,它将无法 GC 老一代。

堆转储显示javafx.scene.Scene#7javafx.scene.Node[]#2 拥有最多的保留空间。如果舞台没有隐藏,两者都不会出现。在引用下,它显示 this[] -> dirtyNodes().

this     - value: javafx.scene.Node[] #2
<- dirtyNodes     - class: javafx.scene.Scene, value: javafx.scene.Node[] #2
 <- value     - class: javafx.scene.Node$ReadOnlyObjectWrapperManualFire, value:  
 javafx.scene.Scene #7

这是什么原因造成的,我该如何解决?

【问题讨论】:

我通过移除舞台上唯一的 GIF 图像,大大减少了隐藏舞台时的内存泄漏量。但是,问题仍然存在。我怀疑隐藏时更新 UI 的后台线程会导致场景/节点保存对旧值的引用。更新此类应用程序的最佳做法是什么?我的应用程序有点像一个聊天应用程序,随时有大约 50 个用户在线。 可能是一个 fx 错误 - 您可以考虑在 fx 问题跟踪器中报告它,最好使用一个简短的可运行示例来演示该行为 我同意@kleopatra,它看起来像一个产品错误,只有开发人员可以帮助你。 JavaFX 错误跟踪在这里:javafx-jira.kenai.com 您能否为此提供MCVE? 嘿,@staticvoid 你有没有找到答案?我可能在我正在开发的 JavaFX 应用程序中遇到类似的情况。 【参考方案1】:

我从来没有找到并回答过这个问题。相反,我会将隐藏的节点设为空,然后将其恢复到视图中。对于密集的动态节点/多个节点,我创建了一个哈希映射来将它们存储在内存中。

这已经成为我在 javafx8 中处理所有图形并重新分配从哈希映射中隐藏和查看的习惯。在现代台式机上,额外的内存和 CPU 使用量可以忽略不计。使用这种方法,我在 win8/10 上隐藏时运行了 0 个 cpu 使用应用程序和低内存应用程序 (~100m)。

【讨论】:

感谢您回来。我的一位同事在我的案例中发现了导致内存泄漏的原因,我认为您的案例也不会发生这种情况。当然,没有必要做你一直在做的事情。但如果它对你有用,那就太好了。【参考方案2】:

Java 具有弱引用等特性:https://docs.oracle.com/javase/7/docs/api/java/lang/ref/WeakReference.html

软参考:https://docs.oracle.com/javase/7/docs/api/java/lang/ref/SoftReference.html

这些允许您专门针对 VM ->> 垃圾收集的内容。

另外,还有并发 API http://winterbe.com/posts/2015/04/07/java8-concurrency-tutorial-thread-executor-examples/

使用执行器服务和线程池。

对于 java 中的内存限制应用程序,软件应该调用

System.gc() // garbage collector

无论其自动调用如何,都以间隔为单位

您可以使用 Runtime 类为项目安排负载均衡器 https://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html

public Process exec(String command)


                throws IOException
//--------------------------------------------------------
    Executes the specified string command in a separate process.

public void gc()

//----------------------------------------------------------
Runs the garbage collector. Calling this method suggests that the Java virtual machine expends effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the virtual machine has made its best effort to recycle all discarded objects
This is a convenience method. An invocation of the form exec(command) behaves in exactly the same way as the invocation exec(command, null, null). 

线程一直是内存密集型应用程序的一个问题,在 JavaFX 中,场景的每个组件都是线程紧密绑定到场景,但在实现时,它似乎是松散绑定的。

如果需要长时间运行,最好在 Native 端 (JNI) 处理一些处理器密集型任务。 此外,CLEAN 架构将受益

https://www.google.co.in/webhp?sourceid=chrome-instant&rlz=1C1CHBF_enIN736IN736&ion=1&espv=2&ie=UTF-8#q=clean+code&*

【讨论】:

我不太喜欢这个答案。关于可能发生的事情有点模糊。真正有趣的部分是大灰色块下方的段落,您从这里开始谈论 Scene,但没有其他特定于 Java FX 的部分。但是,在没有任何其他合理解决方案的情况下,您是赏金的接受者。恭喜。

以上是关于隐藏阶段时的JavaFX 8内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

关于内存屏蔽 和内存泄漏的解决

处理 CGMutablePath 时的内存泄漏

使用 AFHTTPSessionManager 时的内存泄漏

使用图像时的内存泄漏

可以在 Visual Studio 的泄漏检测中隐藏安全的内存泄漏吗?

使用 setText 时的内存泄漏