JavaFX 吃掉了我的记忆?
JavaFX eats my memory?
在对标题感到沮丧之前,我想澄清一下,我是 JavaFX 的新手 UI。我作为一名开发人员已经 9 年了,使用 Swing,目前我决定尝试使用 JavaFX。网上的例子表明,JavaFX 相比Swing 确实可以创建漂亮的GUIs。也许我正在尝试以错误的方式创建和部署 GUIs,但有一件事是肯定的。 JavaFX 窗格的加载速度比 Swing 慢,并且消耗更多的内存。同样的 GUI 是用 JAVAFX 重新设计的,它几乎需要 200Mb 而 Swing GUI 只需要 50Mb.
这里我给出了一个代码示例,说明如何使用 FXML 以编程方式创建 GUIs。
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 classes,一个 class 结合了 FXML Pane 和它的 Controller。 FXMLPane class 的代码如下代码所示。
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 GUIs 的创建比 Swing 慢,而是 RAM 比相应的 Swing 版本多 3 倍和 4 倍。
有人可以向我解释我做错了什么吗? FXML 文件在网格窗格中只有基本组件,如按钮、图层和文本字段等组件。
上面例子的代码可以找到here
总结评论区的答案:
- JavaFX 通常需要更多内存。例如。 JavaFX 对 UI 组件的所有属性使用双精度,而 Swing 大多数时候使用整数值。但差异不应该很明显。
- Java 根据需要消耗更多内存。默认情况下 Java 不会 return 将内存返回给您的系统,即使您触发了垃圾回收。因此,如果 JavaFX 程序在初始化过程中需要大量内存,但随后将其释放,则 JRE 将永远保持最大级别的内存(见图 1)。作为副作用,GC 的触发频率会降低,因为有太多空闲未使用的内存(见图 2)。您可以使用 JVM 选项 -XX:+UseG1GC 更改默认值。这改变了内存分配方式、释放方式以及 GC 触发时间的行为。使用此选项,分配的内存应该更好地适应已使用的内存。如果您想要更多调整,请参阅 Java Heap Tuning
JavaFX相对于Swing是一个新的框架。随着时间的推移,它将在性能和资源消耗方面得到改善。正如您在图 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 周期之后,内存大小被减小以适应实际使用的内存大小。
在对标题感到沮丧之前,我想澄清一下,我是 JavaFX 的新手 UI。我作为一名开发人员已经 9 年了,使用 Swing,目前我决定尝试使用 JavaFX。网上的例子表明,JavaFX 相比Swing 确实可以创建漂亮的GUIs。也许我正在尝试以错误的方式创建和部署 GUIs,但有一件事是肯定的。 JavaFX 窗格的加载速度比 Swing 慢,并且消耗更多的内存。同样的 GUI 是用 JAVAFX 重新设计的,它几乎需要 200Mb 而 Swing GUI 只需要 50Mb.
这里我给出了一个代码示例,说明如何使用 FXML 以编程方式创建 GUIs。
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 classes,一个 class 结合了 FXML Pane 和它的 Controller。 FXMLPane class 的代码如下代码所示。
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 GUIs 的创建比 Swing 慢,而是 RAM 比相应的 Swing 版本多 3 倍和 4 倍。
有人可以向我解释我做错了什么吗? FXML 文件在网格窗格中只有基本组件,如按钮、图层和文本字段等组件。
上面例子的代码可以找到here
总结评论区的答案:
- JavaFX 通常需要更多内存。例如。 JavaFX 对 UI 组件的所有属性使用双精度,而 Swing 大多数时候使用整数值。但差异不应该很明显。
- Java 根据需要消耗更多内存。默认情况下 Java 不会 return 将内存返回给您的系统,即使您触发了垃圾回收。因此,如果 JavaFX 程序在初始化过程中需要大量内存,但随后将其释放,则 JRE 将永远保持最大级别的内存(见图 1)。作为副作用,GC 的触发频率会降低,因为有太多空闲未使用的内存(见图 2)。您可以使用 JVM 选项 -XX:+UseG1GC 更改默认值。这改变了内存分配方式、释放方式以及 GC 触发时间的行为。使用此选项,分配的内存应该更好地适应已使用的内存。如果您想要更多调整,请参阅 Java Heap Tuning
JavaFX相对于Swing是一个新的框架。随着时间的推移,它将在性能和资源消耗方面得到改善。正如您在图 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 周期之后,内存大小被减小以适应实际使用的内存大小。