我之前已经知道有关非静态内部类的内存泄漏的问题。我阅读了问题this和this,但我并不完全明白我的错误。
我的课程如下
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
}
}
}
AddNewProductDialog
(外部)类是一个单例类,它有一个辅助类AddNewProductDialogHelper
。此助手类设置TextInputDialog newProductName
我在调用类build
的{{1}}方法后跟AddNewProductDialog
方法调用show
每次点击按钮以获取用户输入
我希望AddNewProductDialog.getInstance().build().show()
的实例在初始化AddNewProductDialogHelper
newProductName
之后进行垃圾回收
问题是,dialog box
的实例正在堆内存中出现并且没有收集垃圾。每次我点击按钮获取用户输入时,都会创建一个新实例,并且在点击按钮时它会继续起作用
然而,当我评论此代码块时
AddNewProductDialogHelper
可行,之前的实例 会收集垃圾。 为什么评论此代码块有效?
我正在使用VisualVM来检查堆转储
答案 0 :(得分:1)
您正在将这些内部对象作为侦听器添加到侦听器列表中。
因此有一个参考保留给他们。
所以我认为问题不在你声称引起麻烦的部分,而是上面的那一行。只要您不以某种方式从该侦听器列表中删除内部对象,就无法对其进行垃圾回收。
所以解决方案可能很复杂:你应该退后一步并改变你的方法......你需要能够记住这些内部对象,以便你可以在某个时候取消注册它们。
除此之外:奇怪的设计。也很难为我测试。