When the window list changes, I'm calling item.setOnAction(null) on the
"old list" before inserting a new one.
In general it's not a problem because the menu item or button is in a
"context", like a Stage and everything is freed when the stage is closed.
Maybe on long lasting stages.

The code goes like this:

Window.getWindows().addListener((ListChangeListener<? super Window>)
change -> updateWindowList());


private void updateWindowList() {
    Window[] windows = Window.getWindows().toArray(new Window[] {});

    List<MenuItem> items = new ArrayList<>();
    for (Window window : windows) {
        if (window instanceof Stage stage && stage != primaryStage) {
            MenuItem item = new MenuItem();
            item.setText(stage.getTitle());
            item.setOnAction(a -> stage.toFront());
            item.setGraphic(new FontIcon());
            items.add(item);
        }
    }

    for (MenuItem item : btnWindows.getItems()) {
        item.setOnAction(null);
    }

    btnWindows.getItems().setAll(items);
}


Maybe there's a bug, because the old list of items is collectable.



Em sex., 19 de abr. de 2024 às 01:37, John Hendrikx <john.hendr...@gmail.com>
escreveu:

> This probably is a common mistake, however the Weak wrapper is also easy
> to use wrongly.  You can't just wrap it like you are doing in your example,
> because this is how the references look:
>
>      menuItem ---> WeakEventHandler ---weakly---> Lambda
>
> In effect, the Lambda is weakly referenced, and is the only reference, so
> it can be cleaned up immediately (or whenever the GC decides to run) and
> your menu item will stop working at a random time in the future.  The
> WeakEventHandler will remain, but only as a stub (and gets cleaned up when
> the listener list gets manipulated again at a later stage).
>
> The normal way to use a Weak wrapper is to put a reference to the wrapped
> part in a private field, which in your case would not solve the problem.
>
> I'm assuming however that you are also removing the menu item from the
> Open Windows list. This menu item should be cleaned up fully, and so the
> reference to the Stage should also disappear.  I'm wondering why that isn't
> happening?  If the removed menu item remains referenced somehow, then it's
> Action will reference the Stage, which in turns keeps the Stage in memory.
>
> I'd look into the above first before trying other solutions.
>
> --John
>
>
> On 18/04/2024 17:50, Thiago Milczarek Sayão wrote:
>
> I was investigating,
>
> It probably should be menuItem.setOnAction(new WeakEventHandler<>(e ->
> stage.toFront()));
>
> But I bet it's a common mistake. Maybe the setOnAction should mention it?
>
>
>
> Em qui., 18 de abr. de 2024 às 11:54, Andy Goryachev <
> andy.goryac...@oracle.com> escreveu:
>
>> You are correct - the lambda strongly references `stage` and since it is
>> in turn is strongly referenced from the menu item it creates a leak.
>>
>>
>>
>> The lambda is essentially this:
>>
>>
>>
>> menuItem.setOnAction(new H(stage));
>>
>> class $1 implements EventHandler<ActionEvent> {
>>
>>   private final Stage stage;
>>
>>   public $1(Stage s) {
>>
>>     this.stage = s; // holds the reference and causes the leak
>>
>>   }
>>
>>   public void handle(ActionEvent ev) {
>>
>>     stage.toFront();
>>
>>   }
>>
>> }
>>
>>
>>
>> -andy
>>
>>
>>
>> *From: *openjfx-dev <openjfx-dev-r...@openjdk.org> on behalf of Thiago
>> Milczarek Sayão <thiago.sa...@gmail.com>
>> *Date: *Thursday, April 18, 2024 at 03:42
>> *To: *openjfx-dev <openjfx-dev@openjdk.org>
>> *Subject: *Possible leak on setOnAction
>>
>> Hi,
>>
>>
>>
>> I'm pretty sure setOnAction is holding references.
>>
>>
>>
>> I have a "Open Windows" menu on my application where it lists the Stages
>> opened and if you click, it calls stage.toFront():
>>
>>
>>
>> menuItem.seOnAction(e -> stage.toFront())
>>
>>
>>
>> I had many crash reports, all OOM. I got the hprof files and analyzed
>> them - turns out this was holding references to all closed stages.
>>
>>
>>
>> To fix it, I call setOnAction(null) when the stage is closed.
>>
>>
>>
>> I will investigate further and provide an example.
>>
>>
>>
>> -- Thiago.
>>
>

Reply via email to