关闭JavaFX选项卡不会从该选项卡中的ArrayLists和TableViews释放内存 [英] Closing JavaFX tabs doesn't release memory from ArrayLists and TableViews in that tab

查看:141
本文介绍了关闭JavaFX选项卡不会从该选项卡中的ArrayLists和TableViews释放内存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在试图找出为什么我正在研究的基于JavaFX的应用程序占用了大量内存。我注意到每次在应用程序中打开一个新选项卡时内存都会上升,而在我关闭选项卡后它不是GC。我会继续打开和关闭标签,直到它最终耗尽内存并崩溃。

I've been trying to figure out why a JavaFX based application I am working on uses up so much memory. I noticed memory went up each time I opened a new tab in the application, and wasn't being GC after I had closed the tab. I would keep opening and closing tabs until eventually it ran out of memory and crashed.

所以我写了一个非常简单的程序和GUI。代码如下。我发现如果我将TableView中的项设置为null,清除了ArrayList,并实例化了一个具有相同变量名的新ArrayList,那么它只会GC。

So I wrote and tried a very simple program and GUI. The code is below. What I found was that if I set the items in the TableView to null, cleared out the ArrayList, and instantiated a new ArrayList of the same variable name, only then it would GC.

这是Java和/或JavaFX的正常行为吗?正常的是,一旦标签关闭,它不会破坏选项卡中的那些对象? Java 8 / FX的错误?

Is this normal behavior for Java and/or JavaFX? Normal in that it won't "destroy" those objects in a tab once the tab is closed? Bug with Java 8/FX?

import java.util.ArrayList;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.Orientation;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.SplitPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TableView;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class TabTest extends Application {

    ArrayList<String> _list;

    @Override
    public void start(Stage primaryStage) {
        SplitPane split = new SplitPane();
        split.setOrientation(Orientation.VERTICAL);     
        HBox window = new HBox();       
        HBox top = new HBox(20);
        HBox bottom = new HBox(20);
        Group group = new Group();
        TabPane tabPane = new TabPane();
        Button btn = new Button("Create Tab");
        top.getChildren().add(btn);
        bottom.getChildren().add(tabPane);
        btn.setOnAction(new EventHandler<ActionEvent>() {            
            @Override
            public void handle(ActionEvent event) {
                createTabAndList(tabPane);
            }
        });
        split.getItems().addAll(top,bottom);
        window.getChildren().add(split);
        group.getChildren().add(window);
        Scene scene = new Scene(group);
        split.prefWidthProperty().bind(scene.widthProperty());
        split.prefHeightProperty().bind(scene.heightProperty());        
        primaryStage.setScene(scene);
        primaryStage.show();        
    }

    public static void main(String[] args) {
        launch(args);
    }

    public void createTabAndList(TabPane tabPane){
        _list = new ArrayList<String>();
        for(int i = 0; i < 10000000; i++){
            _list.add("Test Test Test");
        }
        TableView<String> tb1 = new TableView<String>();
        tb1.setItems(FXCollections.observableArrayList(_list));
        Tab tab = new Tab("Tab1");
        tab.setContent(tb1);
        tabPane.getTabs().add(tab);
        tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.SELECTED_TAB);        
        tab.setOnClosed(new EventHandler<Event>() {
            @Override
            public void handle(Event arg0) {
                tb1.setItems(null);
                _list.clear();
                _list = new ArrayList<String>();
            }
        });
    }
}


推荐答案

我出于好奇,有点玩你的样品。我在Ubuntu上工作了jdk1.8.60。首先,有一个全局 _list 字段,它自然会永远保留在内存中,除非你专门清理它。为了简化这些事情,我将 _list 设为本地。然后我删除了onClosed处理程序,看看会发生什么。所以方法 createTabAndList 是这样的:

I played with your sample a bit, out of curiosity. I worked on jdk1.8.60 on on Ubuntu. First, there is the global _list field, this remains in the memory forever, naturally, unless you specifically clean it. To simplify the things, I made the _list local. Then I removed the onClosed handler to see what happens. So the method createTabAndList was like this:

public void createTabAndList(TabPane tabPane){
    List<String> _list = new ArrayList<String>(); //_list is local now
    for(int i = 0; i < 10000000; i++){
        _list.add("Test Test Test");
    }
    TableView<String> tb1 = new TableView<String>();
    tb1.setItems(FXCollections.observableArrayList(_list));
    Tab tab = new Tab("Tab1");
    tab.setContent(tb1);
    tabPane.getTabs().add(tab);
    tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.SELECTED_TAB);        
    //tab.setOnClosed(new EventHandler<Event>() {
    //    @Override
    //    public void handle(Event arg0) {
    //        tb1.setItems(null);
    //        _list.clear();
    //        _list = new ArrayList<String>();
    //    }
    //});
}




  1. 新推出的应用消耗8MB。

  2. 创建了1个标签 - 63 MB

  3. 创建了10个标签 - 560 MB - 现在有10个列表实例

  4. 所有10个标签关闭 - 62 MB

  1. Newly started app consumes 8MB.
  2. 1 tab created - 63 MB
  3. 10 tabs created - 560 MB - there are 10 instances of the list now
  4. All 10 tabs closed - 62 MB

实际上,JavaFX似乎保留对最后一个活动标签的引用,包括其内容。在hepdump的参考路径上没有你的代码,它全部在JFX内部。我注意了几次(表,css处理器),JFX缓存了很多不再需要的东西。但是经过一段时间后,或者当记忆力变得稀缺时,它通常会被清理干净。当我再次创建并关闭10个标签时,它从未消耗更多这62 MB。

Indeed, JavaFX seems to keep the reference to the last active tab, including its content. There was non of your code on the reference path in hepdump, it was all in the JFX internals. I noticed it several times (tables, css processor), that JFX caches a lot of stuff that is not needed any more. But it gets typically cleaned up when after some time, or when the memory gets scarce. When I created and closed the 10 tabs several times again, it never consumed more that these 62 MB.

所以,答案是


  • 事实上,JFX记得一些额外的东西,但在合理的范围内。通过重复打开和关闭选项卡,内存不会无限增长。

  • 如果你真的需要内存中的大型数据模型,就像在你的例子中(10M行),那么它是有意义的关闭时清除标签。

这篇关于关闭JavaFX选项卡不会从该选项卡中的ArrayLists和TableViews释放内存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆