This discussion is archived
1 2 Previous Next 18 Replies Latest reply: Jan 29, 2013 9:46 AM by drenda81 Go to original post RSS
  • 15. Re: Heap space with Gui
    drenda81 Newbie
    Currently Being Moderated
    Hi James,
    I made another test to understand the problem of css. I remove the code that add the style to the Scene. I leave only the css in the fxml. After some switch from one view to another the javafx's object CascadeStyle grow.
    This is the tree of allocation: http://justpaste.it/1ufy

    Seems that the style is linked to the scene and not to the anchor panel of the view. This could be a further proof of the fact that it is a bug?

    Thanks
  • 16. Re: Heap space with Gui
    James_D Guru
    Currently Being Moderated
    I created a JIRA: http://javafx-jira.kenai.com/browse/RT-27896

    I have a test case:

    MemoryLeakTest.java
    import java.net.URL;
    
    import javafx.application.Application;
    import javafx.application.Platform;
    import javafx.beans.property.IntegerProperty;
    import javafx.beans.property.SimpleIntegerProperty;
    import javafx.concurrent.Task;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.scene.control.Label;
    import javafx.scene.layout.BorderPane;
    import javafx.stage.Stage;
    
    public class MemoryLeakTest extends Application {
    
         @Override
         public void start(Stage primaryStage) throws Exception {
              System.out.println(com.sun.javafx.runtime.VersionInfo.getRuntimeVersion());
              final URL fxml = getClass().getResource("Test.fxml");
              final String cssLoc = getClass().getResource("test.css").toExternalForm();
              final BorderPane root = new BorderPane();
              final Label label = new Label();
              root.setTop(label);
              final Scene scene = new Scene(root, 600, 400);
              primaryStage.setScene(scene);
              primaryStage.show();
    
              final IntegerProperty count = new SimpleIntegerProperty(1);
              Task<Void> task = new Task<Void>() {
                   @Override
                   protected Void call() throws Exception {
                        while (! isCancelled()) {
                             try {
                                  Thread.sleep(100);
                             } catch (InterruptedException exc) {
                                  if (isCancelled()) {
                                       break ;
                                  }
                             }
                             Platform.runLater(new Task<Void>() {
                                  @Override
                                  public Void call() throws Exception {
                                       final Parent content = FXMLLoader.<Parent>load(fxml);
                                       content.getStylesheets().add(cssLoc);
                                       root.setCenter(content);
                                       return null ;
                                  }
                             });
                             updateMessage("Screen "+count.get()+"\n"+memInfo());
                             count.set(count.get()+1);
                        }
                        return null;
                   }
              };
              label.textProperty().bind(task.messageProperty());
              Thread t = new Thread(task);
              t.setDaemon(true);
              t.start();
         }
         
         private String memInfo() {
              Runtime rt = Runtime.getRuntime();
              long max = rt.maxMemory();
              long total = rt.totalMemory();
              long free = rt.freeMemory() ;
              long used = total - free ;
              return String.format("Max: %,d Total: %,d Used: %,d Free: %,d", max, total, used, free);
         }
    
         public static void main(String[] args) {
              launch(args);
         }
    }
    Test.fxml
    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import javafx.scene.layout.AnchorPane?>
    <?import javafx.scene.layout.VBox?>
    <?import javafx.scene.layout.HBox?>
    <?import javafx.scene.control.TextField?>
    <?import javafx.scene.control.Label?>
    <?import javafx.scene.control.Button?>
    <?import javafx.scene.control.ListView?>
    <?import javafx.collections.FXCollections?>
    <?import javafx.scene.layout.Priority?>
    <?import javafx.scene.control.Control?>
    <?import java.lang.String?>
    <?import java.net.URL?>
    
    <VBox xmlns:fx="http://javafx.com/fxml" styleClass="vbox">
         <children>
              <Label text="Fruits" />
              <TextField promptText="Input Fruit Here">
                   <minHeight><Control fx:constant="USE_PREF_SIZE"/></minHeight>
              </TextField>
    
              <ListView>
                   <items>
                        <FXCollections fx:factory="observableArrayList" fx:id="listItems">
                             <String fx:value="Apples"/>
                             <String fx:value="Oranges"/>
                             <String fx:value="Pears"/>
                             <String fx:value="Bananas"/>
                             <String fx:value="Grapes"/>
                             <String fx:value="Pomegranates"/>
                             <String fx:value="Mangoes"/>
                        </FXCollections>                    
                   </items>
              </ListView>
              <HBox>
                   <children>
                        <Button text="OK"/>
                        <Button text="Cancel"/>
                        <Button text="Help..."/>
                   </children>
              </HBox>
         </children>
    </VBox>
    test.css
    .vbox {
         -fx-border-style : solid ;
         -fx-border-color: cornflowerblue ;
         -fx-border-width: 5 ;
    }
    .label {
         -fx-background-color: cornsilk  ;
    }
    .list-cell:even {
        -fx-background-color: aliceblue ;
        -fx-text-fill: darkgrey  ;
    }
    .list-cell:odd {
         -fx-background-color: azure ;
         -fx-text-fill: darkgrey ;
    }
    .button {
         -fx-base: antiquewhite ;
    }
    The test case takes quite a long time to total failure on my system (about 7000 iterations), but the memory leak is pretty clear to see.

    I think your workaround is to load all your stylesheets at startup and associate them with the Scene. Remove the css from the fxml.
  • 17. Re: Heap space with Gui
    drenda81 Newbie
    Currently Being Moderated
    Hi James,
    thanks for your support. I am happy that with your help we found a bug not yet been reported.
    I'm sorry but maybe I found another strange thing....maybe another bug? I've a simple test case. In my test case there are 2 view (I copy the login example of java fx and I've modify it a bit):

    -Login: there is a button, when you click it you go to the profile view
    -Profile: there is a table with some fake data (100 entry), there is also a button to return to the login view

    The problem: if you switch from login view to profile with clicking the buttons, there is no problem (you can see the objects alive with profile). Check this by switching 10-20 times, the memory don't grow and the gc works fine.
    On the table there is a listener on MouseClick, so if you click on the table if calls the same method of the button to return to the login page: gotoLogin(MouseEvent event) {...}. If you switch several times from profile to login page clicking on the table you can see that the object to type ProfileController are not finalized (I put a log in the finalize() method) so you walk with little steps towards the heap space.
    Seems that the listener of the table refers some data that prevent the gc to finalize the objects.

    Main.java
    package it.test;
    
    import java.net.URL;
    import java.util.ResourceBundle;
    
    import javafx.animation.FadeTransition;
    import javafx.beans.property.SimpleStringProperty;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.fxml.FXML;
    import javafx.fxml.Initializable;
    import javafx.scene.control.Button;
    import javafx.scene.control.CheckBox;
    import javafx.scene.control.Hyperlink;
    import javafx.scene.control.Label;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.TableView;
    import javafx.scene.control.TextArea;
    import javafx.scene.control.TextField;
    import javafx.scene.control.cell.PropertyValueFactory;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.layout.AnchorPane;
    import javafx.util.Duration;
    
    import org.apache.log4j.Logger;
    
    /**
     * Profile Controller.
     */
    public class ProfileController extends AnchorPane implements Initializable {
         private Logger log = Logger.getLogger(ProfileController.class);
    
         @FXML
         private TextField user;
         @FXML
         private TextField phone;
         @FXML
         private TextField email;
         @FXML
         private TextArea address;
         @FXML
         private CheckBox subscribed;
         @FXML
         private Hyperlink logout;
         @FXML
         private Button save;
    
         @FXML
         private Label success;
    
         @FXML
         // fx:id="column1"
         private TableColumn column1; // Value injected by FXMLLoader
    
         @FXML
         // fx:id="column2"
         private TableColumn column2; // Value injected by FXMLLoader
    
         @FXML
         // fx:id="column3"
         private TableColumn column3; // Value injected by FXMLLoader
    
         @FXML
         // fx:id="table"
         private TableView<Person> table; // Value injected by FXMLLoader
    
         private Main application;
    
         public void setApp(Main application) {
              this.application = application;
              user.setText("");
              email.setText("");
              phone.setText("");
    
              address.setText("");
    
              success.setOpacity(0);
         }
    
         @Override
         public void initialize(URL location, ResourceBundle resources) {
              // POPULATE THE TABLE WITH FAKE DATA
              final ObservableList<Person> data = FXCollections.observableArrayList();
              for (int i = 0; i < 100; i++) {
                   data.add(new Person("Jacob", "Smith", "jacob.smith@example.com"));
              }
    
              column1.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
              column2.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
              column3.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));
              table.setItems(data);
    
         }
    
         public void gotoLogin(MouseEvent event) {
              application.gotoLogin();
         }
    
         private void animateMessage() {
              FadeTransition ft = new FadeTransition(Duration.millis(1000), success);
              ft.setFromValue(0.0);
              ft.setToValue(1);
              ft.play();
         }
    
         public static class Person {
              private final SimpleStringProperty firstName;
              private final SimpleStringProperty lastName;
              private final SimpleStringProperty email;
    
              private Person(String fName, String lName, String email) {
                   this.firstName = new SimpleStringProperty(fName);
                   this.lastName = new SimpleStringProperty(lName);
                   this.email = new SimpleStringProperty(email);
              }
    
              public String getFirstName() {
                   return firstName.get();
              }
    
              public void setFirstName(String fName) {
                   firstName.set(fName);
              }
    
              public String getLastName() {
                   return lastName.get();
              }
    
              public void setLastName(String fName) {
                   lastName.set(fName);
              }
    
              public String getEmail() {
                   return email.get();
              }
    
              public void setEmail(String fName) {
                   email.set(fName);
              }
    
         }
    
         @Override
         protected void finalize() throws Throwable {
              super.finalize();
              log.debug("*** FINALIZE Profile***");
         }
    
    }
    LoginController.java
    package it.test;
    
    import java.net.URL;
    import java.util.ResourceBundle;
    
    import javafx.event.ActionEvent;
    import javafx.fxml.FXML;
    import javafx.fxml.Initializable;
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    import javafx.scene.control.PasswordField;
    import javafx.scene.control.TextField;
    import javafx.scene.layout.AnchorPane;
    
    import org.apache.log4j.Logger;
    
    /**
     * Login Controller.
     */
    public class LoginController extends AnchorPane implements Initializable {
         private Logger log = Logger.getLogger(LoginController.class);
    
         @FXML
         TextField userId;
         @FXML
         PasswordField password;
         @FXML
         Button login;
         @FXML
         Label errorMessage;
    
         private Main application;
    
         public void setApp(Main application) {
              this.application = application;
         }
    
         @Override
         public void initialize(URL location, ResourceBundle resources) {
              errorMessage.setText("");
              userId.setPromptText("demo");
              password.setPromptText("demo");
    
         }
    
         public void processLogin(ActionEvent event) {
              application.gotoProfile();
         }
    
         @Override
         protected void finalize() throws Throwable {
              super.finalize();
              log.debug("*** FINALIZE Login***");
         }
    
    }
    ProfileController.java
    package it.test;
    
    import java.net.URL;
    import java.util.ResourceBundle;
    
    import javafx.animation.FadeTransition;
    import javafx.beans.property.SimpleStringProperty;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.fxml.FXML;
    import javafx.fxml.Initializable;
    import javafx.scene.control.Button;
    import javafx.scene.control.CheckBox;
    import javafx.scene.control.Hyperlink;
    import javafx.scene.control.Label;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.TableView;
    import javafx.scene.control.TextArea;
    import javafx.scene.control.TextField;
    import javafx.scene.control.cell.PropertyValueFactory;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.layout.AnchorPane;
    import javafx.util.Duration;
    
    import org.apache.log4j.Logger;
    
    /**
     * Profile Controller.
     */
    public class ProfileController extends AnchorPane implements Initializable {
         private Logger log = Logger.getLogger(ProfileController.class);
    
         @FXML
         private TextField user;
         @FXML
         private TextField phone;
         @FXML
         private TextField email;
         @FXML
         private TextArea address;
         @FXML
         private CheckBox subscribed;
         @FXML
         private Hyperlink logout;
         @FXML
         private Button save;
    
         @FXML
         private Label success;
    
         @FXML
         // fx:id="column1"
         private TableColumn column1; // Value injected by FXMLLoader
    
         @FXML
         // fx:id="column2"
         private TableColumn column2; // Value injected by FXMLLoader
    
         @FXML
         // fx:id="column3"
         private TableColumn column3; // Value injected by FXMLLoader
    
         @FXML
         // fx:id="table"
         private TableView<Person> table; // Value injected by FXMLLoader
    
         private Main application;
    
         public void setApp(Main application) {
              this.application = application;
              user.setText("");
              email.setText("");
              phone.setText("");
    
              address.setText("");
    
              success.setOpacity(0);
         }
    
         @Override
         public void initialize(URL location, ResourceBundle resources) {
              // POPULATE THE TABLE WITH FAKE DATA
              final ObservableList<Person> data = FXCollections.observableArrayList();
              for (int i = 0; i < 100; i++) {
                   data.add(new Person("Jacob", "Smith", "jacob.smith@example.com"));
              }
    
              column1.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
              column2.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
              column3.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));
              table.setItems(data);
    
         }
    
         public void gotoLogin(MouseEvent event) {
              application.gotoLogin();
         }
    
         private void animateMessage() {
              FadeTransition ft = new FadeTransition(Duration.millis(1000), success);
              ft.setFromValue(0.0);
              ft.setToValue(1);
              ft.play();
         }
    
         public static class Person {
              private final SimpleStringProperty firstName;
              private final SimpleStringProperty lastName;
              private final SimpleStringProperty email;
    
              private Person(String fName, String lName, String email) {
                   this.firstName = new SimpleStringProperty(fName);
                   this.lastName = new SimpleStringProperty(lName);
                   this.email = new SimpleStringProperty(email);
              }
    
              public String getFirstName() {
                   return firstName.get();
              }
    
              public void setFirstName(String fName) {
                   firstName.set(fName);
              }
    
              public String getLastName() {
                   return lastName.get();
              }
    
              public void setLastName(String fName) {
                   lastName.set(fName);
              }
    
              public String getEmail() {
                   return email.get();
              }
    
              public void setEmail(String fName) {
                   email.set(fName);
              }
    
         }
    
         @Override
         protected void finalize() throws Throwable {
              super.finalize();
              log.debug("*** FINALIZE Profile***");
         }
    
    }
    Login.fxml
    <?xml version="1.0" encoding="UTF-8"?>
    
    <?import java.lang.*?>
    <?import java.net.*?>
    <?import java.util.*?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.image.*?>
    <?import javafx.scene.layout.*?>
    <?import javafx.scene.paint.*?>
    
    <AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="500.0" prefWidth="500.0" styleClass="background" xmlns:fx="http://javafx.com/fxml" fx:controller="it.test.LoginController">
      <children>
        <AnchorPane id="anchorPane2" prefHeight="300.0" prefWidth="500.0" styleClass="top-segment" AnchorPane.bottomAnchor="200.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
          <children>
            <VBox id="VBox" alignment="CENTER" prefHeight="300.0" prefWidth="421.0" spacing="5.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="29.0" AnchorPane.rightAnchor="40.0" AnchorPane.topAnchor="0.0">
              <children>
                <AnchorPane id="AnchorPane" prefHeight="180.0" prefWidth="430.0">
                  <children>
                    <Label id="label1" layoutX="14.0" layoutY="67.0" text="Username" />
                    <TextField id="textField1" fx:id="userId" layoutY="86.0" prefWidth="415.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="0.0" />
                    <Label id="label1" layoutX="14.0" layoutY="139.0" text="Password" />
                    <PasswordField id="passwordField1" fx:id="password" layoutY="157.0" prefWidth="415.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="0.0" />
                    <ImageView id="app-login-logo" layoutY="-12.0">
                      <image>
                        <Image url="@LoginLogo.png" preserveRatio="true" smooth="true" />
                      </image>
                    </ImageView>
                  </children>
                </AnchorPane>
              </children>
            </VBox>
          </children>
        </AnchorPane>
        <Button id="button1" fx:id="login" defaultButton="true" onAction="#processLogin" prefHeight="70.0" prefWidth="400.0" text="Login" AnchorPane.bottomAnchor="66.0" AnchorPane.leftAnchor="40.0" AnchorPane.rightAnchor="40.0" />
        <HBox id="hBox1" alignment="CENTER" prefHeight="25.0" prefWidth="418.0" AnchorPane.bottomAnchor="156.0" AnchorPane.leftAnchor="41.0" AnchorPane.rightAnchor="41.0">
          <children>
            <Label id="label2" fx:id="errorMessage" />
          </children>
        </HBox>
      </children>
      <stylesheets>
        <URL value="@Login.css" />
      </stylesheets>
    </AnchorPane>
    Profile.fxml
    <?xml version="1.0" encoding="UTF-8"?>
    <?import java.lang.*?>
    <?import java.net.*?>
    <?import javafx.geometry.*?>
    <?import javafx.scene.control.*?>
    <?import javafx.scene.layout.*?>
    <?import javafx.scene.shape.*?>
    <?import javafx.scene.text.*?>
    
    <AnchorPane id="Profile" minWidth="800.0" prefHeight="800.0" prefWidth="500.0" styleClass="background" xmlns:fx="http://javafx.com/fxml" fx:controller="it.test.ProfileController">
      <children>
        <AnchorPane id="anchorPane1" prefHeight="371.0" prefWidth="500.0" styleClass="top-segment" AnchorPane.bottomAnchor="129.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
          <children>
            <VBox id="VBox" alignment="CENTER" spacing="5.0" AnchorPane.bottomAnchor="32.5" AnchorPane.leftAnchor="42.0" AnchorPane.rightAnchor="40.0" AnchorPane.topAnchor="10.0">
              <children>
                <GridPane id="GridPane" hgap="15.0" vgap="15.0">
                  <children>
                    <Label id="Label" styleClass="profileTitle" text="Please review your profile." GridPane.columnIndex="0" GridPane.columnSpan="2147483647" GridPane.rowIndex="1">
                      <font>
                        <Font size="20.0" fx:id="x1" />
                      </font>
                    </Label>
                    <Label id="Label" font="$x1" text="User:" GridPane.columnIndex="0" GridPane.rowIndex="2">
                      <GridPane.margin>
                        <Insets top="2.0" fx:id="x3" />
                      </GridPane.margin>
                    </Label>
                    <TextField fx:id="user" editable="false" minWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="2" />
                    <Label id="Label" font="$x1" text="Email:" GridPane.columnIndex="0" GridPane.margin="$x3" GridPane.rowIndex="3" />
                    <TextField fx:id="email" minWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="3" />
                    <Label id="Label" font="$x1" text="Phone:" GridPane.columnIndex="0" GridPane.margin="$x3" GridPane.rowIndex="4" />
                    <TextField fx:id="phone" minWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="4" />
                    <Label id="Label" font="$x1" text="Address:" GridPane.columnIndex="0" GridPane.rowIndex="5" GridPane.valignment="TOP">
                      <GridPane.margin>
                        <Insets top="8.0" />
                      </GridPane.margin>
                    </Label>
                    <TextArea fx:id="address" maxHeight="82.0" minHeight="82.0" minWidth="200.0" prefHeight="82.0" GridPane.columnIndex="1" GridPane.rowIndex="5" />
                    <CheckBox id="" fx:id="subscribed" GridPane.columnIndex="1" GridPane.rowIndex="6">
                      <font>
                        <Font size="16.0" fx:id="x2" />
                      </font>
                      <GridPane.margin>
                        <Insets left="1.0" />
                      </GridPane.margin>
                    </CheckBox>
                    <Label id="Label" font="$x1" text="Subscribe to newsletter" GridPane.columnIndex="1" GridPane.rowIndex="6">
                      <GridPane.margin>
                        <Insets left="28.0" top="3.0" />
                      </GridPane.margin>
                    </Label>
                  </children>
                  <columnConstraints>
                    <ColumnConstraints hgrow="NEVER" minWidth="60.0" />
                    <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" />
                  </columnConstraints>
                  <rowConstraints>
                    <RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
                    <RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
                    <RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
                    <RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
                    <RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
                    <RowConstraints minHeight="10.0" vgrow="SOMETIMES" />
                  </rowConstraints>
                </GridPane>
                <TableView fx:id="table" onMouseClicked="#gotoLogin" prefHeight="252.5" prefWidth="718.0">
                  <columns>
                    <TableColumn prefWidth="75.0" text="Column 1" fx:id="column1" />
                    <TableColumn prefWidth="75.0" text="Column 2" fx:id="column2" />
                    <TableColumn prefWidth="75.0" text="Column 3" fx:id="column3" />
                  </columns>
                </TableView>
              </children>
            </VBox>
          </children>
        </AnchorPane>
        <HBox id="HBox" alignment="CENTER" spacing="5.0" AnchorPane.bottomAnchor="102.0" AnchorPane.leftAnchor="40.0" AnchorPane.rightAnchor="40.0">
          <children>
            <Label fx:id="success" font="$x2" opacity="0.0" text="Profile  successfully updated!" />
          </children>
        </HBox>
        <HBox id="HBox" alignment="CENTER" spacing="20.0" AnchorPane.bottomAnchor="42.0" AnchorPane.leftAnchor="40.0" AnchorPane.rightAnchor="40.0" />
        <Button fx:id="save" defaultButton="true" font="$x1" layoutX="281.0" layoutY="687.0" maxHeight="2.147483647E9" onMouseClicked="#gotoLogin" prefHeight="50.0" prefWidth="205.0" text="Return to login" />
      </children>
      <stylesheets>
        <URL value="@Login.css" />
      </stylesheets>
    </AnchorPane>
    Thanks very much

    Edited by: drenda81 on 25-gen-2013 1.14
  • 18. Re: Heap space with Gui
    drenda81 Newbie
    Currently Being Moderated
    Hi,
    no one has tried my example?

    Thanks!
1 2 Previous Next

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points