【问题标题】:JavaFX eats my memory?JavaFX 吃掉我的记忆?
【发布时间】:2015-05-05 22:27:41
【问题描述】:

在对标题感到沮丧之前,我想澄清一下我是 JavaFX UI 的新手。我作为一名开发人员已经 9 年了,使用 Swing,目前我决定尝试使用 JavaFX。网上的例子表明,与 Swing 相比,JavaFX 确实可以创建漂亮的 GUI。也许我试图以错误的方式创建和部署 GUI,但有一件事是肯定的。 JavaFX 窗格的加载速度比 Swing 慢,并且消耗更多的内存。使用 JAVAFX 重新设计了相同的 GUI,它需要将近 200Mb,而 Swing GUI 只需要 50Mb。

这里我给出一个代码示例,说明如何使用 FXML 以编程方式创建 GUI。

public class PanelCreator {

   private FXMLPane<LoginPaneController>           loginFXML;
   private FXMLPane<RegistrationPaneController>    registerFXML;
   private FXMLPane<EmailValidationPaneController> emailValidationFXML;

   public PanelCreator() {
      this.rootPane = rootPane;
      try {
        loginFXML           = new FXMLPane<LoginPaneController>("Login.fxml");
        registerFXML        = new FXMLPane<RegistrationPaneController>("Register.fxml");
        emailValidationFXML = new FXMLPane<EmailValidationPaneController>("EmailValidation.fxml");
      } catch (IOException e) {e.printStackTrace();} // catch
   } // Constructor Method

   public Pane getLoginPane() {
      return loginFXML.getPane();
   } // getLoginPane()

   public Pane getRegisterPane() {
      return registerFXML.getPane();
   } // getRegisterPane

   public Pane getEmailValidationPane() {
      return emailValidationFXML.getPane();
   } // getEmailValidationPane

   public LoginPaneController getLoginPaneController() {
      return loginFXML.getController();
   } // getLoginPaneController()

   public RegistrationPaneController getRegistrationPaneController() {
      return registerFXML.getController();
   } // getRegistrationPaneController()
} // class PanelCreator

PanelCreator 的构造方法创建了 3 个 FXMLPane 类,一个结合了 FXML Pane 和它的 Controller 的类。 FXMLPane 类的代码如下所示。

public class FXMLPane<T> {

    private Pane pane;
    private T paneController;

    public FXMLPane(String url) throws IOException {
        URL location = getClass().getResource(url);
        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setLocation(location);
        fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
        pane = fxmlLoader.load(location.openStream());
        paneController = fxmlLoader.<T>getController();
    } // Constructor Method

    public Pane getPane() {
        return pane;
    } // getPane()

    public T getController() {
        return paneController;
    } // getController()
}

现在通过 PanelCreator,我可以使用 get 方法来获取每个 JavaFX 面板及其控制器,而且我不必每次都运行 FXML 加载方法来获取面板。目前,困扰我的不是 FXML GUI 的创建比 Swing 慢,而是 RAM 是相应 Swing 版本的 3 倍和 4 倍。

有人可以向我解释我做错了什么吗? FXML 文件在网格窗格上只有基本组件,如按钮、图层和文本字段等组件。

上面例子的代码可以找到here

【问题讨论】:

  • 你检查过堆真的被消耗了吗?如果 Java 有时需要它,它会消耗本机内存,但从不将其返回给操作系统(因为从性能的角度来看它更好)。那么您是否尝试打印还剩多少堆?
  • 是的,我明白你的意思了。在我的 PC 上使用 Java 8u40,Swing 版本使用大约 30MB,FX 使用大约 70MB。看起来 FX 是一个更重的工具包。十年前这也会让我担心,但今天即使是拥有 GB RAM 的手机也不应该成为问题,我认为?还要考虑到 FX 具有 Swing 所没有的特性/能力,这会使它变得更重。
  • @jewelsea 有什么建议吗?
  • @tomsontom 有什么建议吗?
  • 我运行您的应用程序,将最大堆内存大小限制为允许应用程序启动的最小大小 - 在 OS X Java 8u40 上,对于 Swing 程序,这是 4Mb java -Xmx4m,对于 JavaFX程序,这是 8Mb java -Xmx8m。因此,Swing 和 JavaFX 程序都能够以相当小的 Java 堆空间使用量运行。

标签: performance user-interface memory javafx javafx-8


【解决方案1】:

总结评论部分的答案:

  • JavaFX 通常需要更多内存。例如。 JavaFX 对 UI 组件的所有属性使用双精度,而 Swing 大部分时间使用整数值。但差异不应该是明显的。
  • Java 会根据需要消耗更多内存。默认情况下,即使您触发了垃圾回收,Java 也不会将内存返回给您的系统。因此,如果 JavaFX 程序在初始化过程中需要大量内存,但随后将其释放,则 JRE 将永远保持最大内存水平(见图 1)。作为副作用,GC 的触发频率会降低,因为有很多空闲的未使用内存(见图 2)。您可以使用 JVM 选项 -XX:+UseG1GC 更改默认值。这会改变内存的分配方式、释放方式以及触发 GC 的方式。使用此选项,分配的内存应该更好地适应使用的内存。如果您想要更多调整,请参阅Java Heap Tuning
  • 与 Swing 相比,JavaFX 是一个新框架。它将随着时间的推移在性能和资源消耗方面得到改善。正如您在图 1 和图 3 中看到的,它已经得到了改进。它现在在 64 位 Linux 机器上使用 8 到 9MB 的内存。这比 Swing 版本的内存还要少。我用的是 Oracle Java

    java version "1.8.0_111"
    Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
    Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)
    

图 1:JavaFX 示例程序随时间的内存消耗。与已用内存相比,它显示了大量可用内存。多次手动触发GC,显示已用内存部分没有垃圾。

图 2:JavaFX 示例程序随时间的内存消耗,但没有手动触发 GC。使用的内存越来越大,因为没有触发 GC。

图 3:使用 GC 选项 -XX:+UseG1GC 的 JavaFX 示例程序随时间的内存消耗。在第一次 GC 循环之后,内存大小被减小以适合实际使用内存的大小。

【讨论】:

  • !!! - 至少对我来说,可以让 JVM 真正缩减它从操作系统保留的内存的启示是一个突破。对我来说,另一种行为长期以来一直是 Java 的主要批评者。任何有针对性的文本链接,专门讨论实现该行为?
  • 我发现以下总结文章很有帮助:stefankrause.net/wp/?p=14。有了这样的配置,我就不必过多地避免使用基于 JVM 的工具了。
  • @naki 我刚刚使用 --XX:+UseG1GC 进行了测试。当我手动 GC 时,我看到与上图相同的内容,但根据操作系统(通过查看顶部或 MacOS 活动监视器),该应用程序仍在消耗与以前相同的内容(在我的情况下约为 200MB,而 visualVM 说分配的堆只有大约 63MB)。我正在使用 Java 8 进行测试,稍后将使用 Java 14 进行检查,看看情况是否更好。
猜你喜欢
  • 2012-12-20
  • 2011-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-08
相关资源
最近更新 更多