<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
</head>
<body>
<div dir="ltr" style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Spoke too soon: we already have </div>
<div dir="ltr" style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<a href="https://bugs.openjdk.org/browse/JDK-8184166" data-outlook-id="374b16ff-53cf-48f4-9416-33de9096ced2">https://bugs.openjdk.org/browse/JDK-8184166</a></div>
<div dir="ltr" style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
from 2017.</div>
<div dir="ltr" style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div dir="ltr" style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Question: are there any more places where we don't null the unused entries?</div>
<div dir="ltr" style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div dir="ltr" style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
-andy</div>
<div dir="ltr" style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div id="mail-editor-reference-message-container">
<div dir="ltr" class="ms-outlook-mobile-reference-message skipProofing"></div>
<div class="ms-outlook-mobile-reference-message skipProofing" style="text-align: left; padding: 3pt 0in 0in; border-width: 1pt medium medium; border-style: solid none none; border-color: rgb(181, 196, 223) currentcolor currentcolor; font-family: Aptos; font-size: 12pt; color: black;">
<b>From: </b>openjfx-dev <openjfx-dev-retn@openjdk.org> on behalf of Andy Goryachev <andy.goryachev@oracle.com><br>
<b>Date: </b>Thursday, December 4, 2025 at 11:40<br>
<b>To: </b>John Hendrikx <john.hendrikx@gmail.com>, openjfx-dev@openjdk.org <openjfx-dev@openjdk.org><br>
<b>Subject: </b>Re: SortedList hanging on to references & preventing GC<br>
<br>
</div>
<div dir="ltr" class="ms-outlook-mobile-reference-message skipProofing"><span style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">>
</span><span style="font-family: Aptos; font-size: 16px; color: rgb(33, 33, 33);">Time pressure and insufficient testing.</span></div>
<div dir="ltr" class="ms-outlook-mobile-reference-message skipProofing" style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div dir="ltr" class="ms-outlook-mobile-reference-message skipProofing" style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Alas! I can create a ticket, unless someone has already created one.</div>
<div dir="ltr" class="ms-outlook-mobile-reference-message skipProofing" style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div dir="ltr" class="ms-outlook-mobile-reference-message skipProofing" style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
-andy</div>
<div dir="ltr" class="ms-outlook-mobile-reference-message skipProofing" style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div dir="ltr" class="ms-outlook-mobile-reference-message skipProofing" style="font-family: "Iosevka Fixed SS16", Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div id="mail-editor-reference-message-container">
<div class="ms-outlook-mobile-reference-message skipProofing" style="text-align: left; padding: 3pt 0in 0in; border-width: 1pt medium medium; border-style: solid none none; border-color: rgb(181, 196, 223) currentcolor currentcolor; font-family: Aptos; font-size: 12pt; color: black;">
<b>From: </b>openjfx-dev <openjfx-dev-retn@openjdk.org> on behalf of John Hendrikx <john.hendrikx@gmail.com><br>
<b>Date: </b>Thursday, December 4, 2025 at 11:18<br>
<b>To: </b>openjfx-dev@openjdk.org <openjfx-dev@openjdk.org><br>
<b>Subject: </b>Re: SortedList hanging on to references & preventing GC<br>
<br>
</div>
<p class="ms-outlook-mobile-reference-message skipProofing">This looks like a classic problem where unused elements in an array are not nulled. Looking at the code that updates the `size` field, there are a few code paths that are not setting unused elements
to null. I also saw no code that ever shrinks the arrays. So it looks this implementation is only half finished.</p>
<p class="ms-outlook-mobile-reference-message skipProofing">So, yes, I'd say this is a bug.</p>
<blockquote>
<div class="ms-outlook-mobile-reference-message skipProofing">I'm going to guess there's a very good reason for this behaviour.</div>
</blockquote>
<div class="ms-outlook-mobile-reference-message skipProofing">Time pressure and insufficient testing.</div>
<p class="ms-outlook-mobile-reference-message skipProofing">--John</p>
<div class="moz-cite-prefix">On 04/12/2025 19:40, Cormac Redmond wrote:</div>
<blockquote>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;">Hi,</div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;"><br>
</div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;">I've traced a memory issue back to a SortedList (surprisingly), where it's hanging on to objects that could/should have been GC'd.</div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;"><br>
</div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;">SortedList's internal arrays will only grow (but not shrink) in line with the source ObservableList (I'm sure there are reasons for this). So even when your source ObservableList
shrinks, SortedList is hanging on to references to objects the source list once contained, even though they're completely removed from the source list.</div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;"><br>
</div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;">This leads to a substantial waste of memory, especially when just one momentarily large dataset leads to a permanent spike in unnecessary memory usage for the remainder for the application's
lifetime. I'm sure I'm not the first to raise this or ask about it & I'm going to guess there's a very good reason for this behaviour. But could someone explain this? I would have thought SortedList should/could remain as lean as the source list. FilteredList
is somewhat similar, except it stores an array of ints (indexes), so less of a memory hit, but still pointless nonetheless.</div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;"><br>
</div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;">Example GIF + code below: setup a typical sortable table (so, ObservableList + FilteredList + SortableList), where the print button shows that when you add a lot of data, and remove
it, SortedList retains references to all of the old objects. Some reflection is used to print that information.</div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;"><br>
</div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;"><img src="cid:part1.Wj8uTVDa.rJ3j4SWw@gmail.com" alt="sorted_list_mem.gif" width="406" height="562" style="width: 406px; height: 562px;"></div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;"><br>
</div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;"><br>
</div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;">Code to reproduce:</div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;"><br>
</div>
<div dir="ltr" class="gmail_default" style="font-family: monospace;">public class SortedListMemWasteDemo extends Application {<br>
<br>
record PotentialLargeData(String info) {}<br>
<br>
public static void main(String[] args) {<br>
launch(args);<br>
}<br>
<br>
@Override<br>
public void start(Stage primaryStage) {<br>
ObservableList<PotentialLargeData> masterData = FXCollections.observableArrayList(<br>
new PotentialLargeData("Initial info 1"),<br>
new PotentialLargeData("Initial info 2"));<br>
<br>
TableColumn<PotentialLargeData, String> col = new TableColumn<>("Info");<br>
col.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().info()));<br>
<br>
TableView<PotentialLargeData> table = new TableView<>();<br>
table.getColumns().add(col);<br>
<br>
FilteredList<PotentialLargeData> filteredData = new FilteredList<>(masterData, item -> true);<br>
SortedList<PotentialLargeData> sortedData = new SortedList<>(filteredData);<br>
sortedData.comparatorProperty().bind(table.comparatorProperty());<br>
table.setItems(sortedData);<br>
<br>
Button loadManyBtn = new Button("Add 10,000 items");<br>
loadManyBtn.setOnAction(e -> {<br>
System.out.println("Adding 10000 items to master data");<br>
masterData.clear();<br>
for (int i = 0; i < 10000; i++) masterData.add(new PotentialLargeData("Info item " + i));<br>
});<br>
<br>
Button reduceBtn = new Button("Reduce to 2");<br>
reduceBtn.setOnAction(e -> {<br>
System.out.println("Reducing master data size to 2");<br>
masterData.setAll(new PotentialLargeData("New info 1"), new PotentialLargeData("New info 2"));<br>
});<br>
<br>
Button printBtn = new Button("Print interal sizes");<br>
printBtn.setOnAction(e -> {<br>
try {<br>
System.out.println("Items the user sees: " + sortedData.size());<br>
int[] filtered = (int[]) getFieldValue(filteredData, "filtered");<br>
System.out.println("FilteredList.filtered length: " + filtered.length);<br>
// This is a hidden and significant waste of memory<br>
Object[] sorted = (Object[]) getFieldValue(sortedData, "sorted");<br>
System.out.println("SortedList.sorted length: " + sorted.length);<br>
} catch (Exception ex) {<br>
throw new RuntimeException(ex);<br>
}<br>
});<br>
<br>
primaryStage.setScene(new Scene(new VBox(table, loadManyBtn, reduceBtn, printBtn), 600, 400));<br>
primaryStage.show();<br>
}<br>
<br>
private static Object getFieldValue(Object object, String fieldName) throws Exception {<br>
Field field = object.getClass().getDeclaredField(fieldName);<br>
field.setAccessible(true);<br>
return field.get(object);<br>
}<br>
}</div>
<div dir="ltr" class="gmail_default" style="font-family: monospace;"><br>
</div>
<div dir="ltr" class="gmail_default" style="font-family: monospace;"><br>
</div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;">Kind Regards,</div>
<div dir="ltr" class="gmail_default" style="font-family: verdana, sans-serif;">Cormac</div>
</blockquote>
</div>
</div>
</body>
</html>