Reputation: 1966
I know questions regarding memory leak for non-static inner classes have already been asked before. I read questions this and this but I don't fully understand what wrong am I doing.
My class is as below
public class AddNewProductDialog {
private static AddNewProductDialog dialog;
private TextInputDialog newProductName = new TextInputDialog();
private AddNewProductDialog(){
}
public static AddNewProductDialog getInstance(){
if(dialog == null){
dialog = new AddNewProductDialog();
}
return dialog;
}
/*Helper Class start*/
private class AddNewProductDialogHelper{
private void initializeDialog(){ //---> Prepare a dialog box
newProductName.setTitle("Add New Product");
newProductName.setHeaderText("Note: This product name will be used as bat script file name. Eg. call_<productname>_script");
newProductName.setContentText("Product Name :");
newProductName.getDialogPane().lookupButton(ButtonType.OK).setDisable(true);
/*Something over here*/
newProductName.getEditor().textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
// TODO Auto-generated method stub
if(isInputvalid(newProductName.getEditor().getText())){
newProductName.getDialogPane().lookupButton(ButtonType.OK).setDisable(false);
}
}
});
}
private boolean isInputvalid(String text){
if(text.trim().length() > 0)
return true;
return false;
}
}
/*Helper class end*/
public AddNewProductDialog build(){
new AddNewProductDialogHelper().initializeDialog();
return this;
}
public void show() {
Optional<String> result = newProductName.showAndWait();
if(result.isPresent()){
//----> handle the input
}
}
}
The AddNewProductDialog
(outer) class is a singleton class which has a helper class AddNewProductDialogHelper
. This helper class sets the properties of TextInputDialog newProductName
I am calling the build
method of class AddNewProductDialog
followed by show
method as AddNewProductDialog.getInstance().build().show()
everytime a button is clicked to take user input.
I want the instance of the AddNewProductDialogHelper
to be garbage collected after it is done initializing newProductName
dialog box
The problem is that, the instances of AddNewProductDialogHelper
are pilling up in Heap memory and are not getting garbage collected. Everytime I click the button to get user input a new instance is getting created and it keeps on pilling up as the button is clicked
However, when I comment this code block
newProductName.getEditor().textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
// TODO Auto-generated method stub
if(isInputvalid(newProductName.getEditor().getText())){
newProductName.getDialogPane().lookupButton(ButtonType.OK).setDisable(false);
}
}
});
it works and previous instances are getting garbage collected. Why does commenting this code block works?
I am using VisualVM to check my heap dump
Upvotes: 0
Views: 269
Reputation: 140573
You are adding those inner objects as listeners to a listener list.
Thus there is a reference kept to them.
So I think the problem is not in the section that you claim to cause trouble, but the line above. As long as you don't somehow remove the inner objects from that listener list they can't be garbage collected.
So the solution is probably complicated: you should step back and change your approach... You need to be able to remember these inner objects so that you can unregister them at some point.
And beyond that: strange design. Also looks hard to test for me.
Upvotes: 1