gpt4 book ai didi

memory - JavaFX 和监听器内存泄漏

转载 作者:行者123 更新时间:2023-12-01 03:49:18 25 4
gpt4 key购买 nike

我对 JavaFx 8 和监听器内存泄漏问题有点困惑。官方doc说:

The ObservableValue stores a strong reference to the listener which will prevent the listener from being garbage collected and may result in a memory leak.



我想举个例子说明 ObservableValue<T> 的用法 addListener方法造成内存泄漏。

例如,如果我有一个这样的类:
public class ConfigurationPane extends AnchorPane {
@FXML
private Label titleLabel;

public ConfigurationPane () {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("view/ConfigurationPane .fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException e) {
e.printStackTrace();
}
}

@FXML
private void initialize() {
titleLabel.sceneProperty().addListener(new MyListener());
}
}

我可以得到内存泄漏吗?当 ConfigurationPane对象被垃圾回收, MyListener对象也被垃圾收集了吗?我无法看到一个场景

a strong reference to the listener will prevent the listener from being garbage collected



附言我看到其他 S.O.关于这个的问题,但这些都没有帮助我理解这个问题。

谢谢。

最佳答案

这意味着存储您的监听器的映射没有使用弱引用,您必须自己删除监听器以避免内存泄漏。

在下面的示例中,LeakingListener 对象将永远不会被释放,尽管相应的 TextFields 被从场景中删除:

public class LeakListener extends Application {

private static class LeakingListener implements InvalidationListener {

private final TextField tf;
private final int[] placeHolder = new int[50000]; // to simplify monitoring

public LeakingListener(TextField tf) {
this.tf = tf;
}

public void invalidated(Observable i) {
tf.setText(tf.getText() + ".");
}
}

@Override
public void start(Stage primaryStage) {
final Pane root = new VBox(3);

final Button btnType = new Button("Type in all");

Button btnAdd = new Button("Add");
btnAdd.setOnAction((e) -> {
TextField tf = new TextField();
root.getChildren().add(tf);
// memory leaking listener which never gets cleaned
btnType.armedProperty().addListener(new LeakingListener(tf));
});

Button btnRemove = new Button("Remove");
btnRemove.setOnAction((ActionEvent e) -> {
// find random TextEdit element
Optional<Node> toRemove = root.getChildren().stream().filter((Node t) -> t instanceof TextField).findAny();
// if any, and remove it
if (toRemove.isPresent()) {
root.getChildren().remove(toRemove.get());
}
});

Button btnMemory = new Button("Check Memory");
btnMemory.setOnAction((e) -> {
System.gc();
System.out.println("Free memory (bytes): " + Runtime.getRuntime().freeMemory());
});

root.getChildren().addAll(btnAdd, btnRemove, btnType, btnMemory);
Scene scene = new Scene(root, 200, 350);
primaryStage.setScene(scene);
primaryStage.show();
}
}

ObservableValue专卖店 weak reference对于听众来说,你不会有问题。可以通过下一个示例来模仿它:

public class LeakListener extends Application {

private static class NonLeakingListener implements InvalidationListener {

// we need listener to don't hold reference on TextField as well
private final WeakReference<TextField> wtf;
private final int[] placeHolder = new int[10000];

public NonLeakingListener(TextField tf) {
this.wtf = new WeakReference<>(tf);
}

public void invalidated(Observable i) {
if (wtf.get() != null) {
wtf.get().setText(wtf.get().getText() + ".");
}
}
}

@Override
public void start(Stage primaryStage) {
final Pane root = new VBox(3);

final Button btnType = new Button("Type in all");

// Here is rough weak listeners list implementation
WeakHashMap<TextField, NonLeakingListener > m = new WeakHashMap<>();
btnType.armedProperty().addListener((e)-> {
for (TextField tf : m.keySet()) {
m.get(tf).invalidated(null);
}
});


Button btnAdd = new Button("Add");
btnAdd.setOnAction((e) -> {
TextField tf = new TextField();
root.getChildren().add(tf);
m.put(tf, new NonLeakingListener(tf));
});

Button btnRemove = new Button("Remove");
btnRemove.setOnAction((e) -> {
// find random TextEdit element
Optional<Node> toRemove = root.getChildren().stream().filter((Node t) -> t instanceof TextField).findAny();
// if any, and remove it
if (toRemove.isPresent()) {
root.getChildren().remove(toRemove.get());
}
});

Button btnMemory = new Button("Check Memory");
btnMemory.setOnAction((e)-> {
System.gc();
System.out.println("Free memory (bytes): " + Runtime.getRuntime().freeMemory());
});

root.getChildren().addAll(btnAdd, btnRemove, btnType, btnMemory);
Scene scene = new Scene(root, 200, 350);
primaryStage.setScene(scene);
primaryStage.show();
}
}

关于memory - JavaFX 和监听器内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24372622/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com