JDK-8357473 : Compilation spike leaves many CompileTasks in free list
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 25
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2025-05-21
  • Updated: 2025-07-14
  • Resolved: 2025-07-09
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 26
26 b06Fixed
Related Reports
Blocks :  
Blocks :  
Causes :  
Relates :  
Description
This is a problem in mainline, but it would be more important for Leyden. CompileTask are never destructed. Freed CompileTasks are queued in the free list, and stay there indefinitely.

So, if we have a compilation spike where many compile tasks are created, all these tasks would end up on free list once compilation is finished. In Leyden, is it "normal" to have thousands of CompileTasks during the initial AOT load.

Each CompileTask is not small, about 160+ bytes. This means 1K of these tasks would take 160KB worth of native memory, forever. Every time we add another field to CompileTask, it would make this loss even greater. I found this when doing JDK-8231269, that added some padding around hot fields, greatly increasing CompileTask footprint. The additional RSS was closer to +1 MB on my Leyden experiments. This is... sub-optimal.

There are two ways out of this:
 1. Put a cap on the number of CompileTasks we maintain in the free list.
 2. Ditch the free list completely, and rely on new/delete on demand.

It is tempting to go (2), because CompileTask creation should be rare enough, and the associated AOT/JIT costs are large in comparison with native allocs. It would also help Leyden, since we would not have to take the CompileTaskAlloc_lock to manage the free list.

The two pecularities are: a) each CompileTask also has Mutex associated with it, and so we likely want to avoid too much churn on them (see also JDK-8357481); b) current Leyden uses CompileTasks free list coding to check if all created CompileTasks have competed during assembly. It would require some light re-engineering to fit.

So if (2) is insurmountable, we can go (1).
Comments
I re-opened JDK-8361752 for the TestStressBailout.java failures.
14-07-2025

> This RFE might have just exposed another path to NMT problem thorough actually calling free() for CompileTasks now Hi [~shade] this could be, I thought the same that your change just exposed an existing issue.
11-07-2025

Let's see if this issue persists after JDK-8360048 integrates. Yes, it is suspicious there is a crash on CompileBroker path, I see Oracle testing found some as well: JDK-8361752, closed as duplicate of JDK-8360048. The middle of stack traces look different, but all of them lead to NMT. This RFE might have just exposed another path to NMT problem by actually calling free() for CompileTasks now. Before this change, CompileTasks were not free-ed at all.
11-07-2025

Hi [~chagedorn] the backtrace of JDK-8360048 looks very different. And we saw 2 failures in a row today and yesterday; so I would guess the fatal error I reported here has probably to do with recent changes (but that's no scientific proof of course, just a guess looking at the stack and the occurrences). However https://bugs.openjdk.org/browse/JDK-8361752 seems to be the same issue I saw.
11-07-2025

[~mbaesken] there was already an earlier report here before this went in: JDK-8360048. Could it be the same?
11-07-2025

We get now failures in test compiler/debug/TestStressBailout.java (only on Windows x86_64 so far; fastdebug binaries are used). # Internal Error (d:\priv\jenkins\client-home\workspace\openjdk-jdk-dev-windows_x86_64-dbg\jdk\src\hotspot\share\nmt/mallocHeader.inline.hpp:107), pid=7084, tid=38224 # fatal error: NMT corruption: Block at 0x00000282c97f0640: header canary broken Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) V [jvm.dll+0xd1b28a] MallocHeader::resolve_checked+0x18a (mallocHeader.inline.hpp:113) V [jvm.dll+0xd1acb1] MallocTracker::record_free_block+0x41 (mallocTracker.cpp:208) V [jvm.dll+0xe23986] os::free+0x76 (os.cpp:780) V [jvm.dll+0x5faf2a] CompileQueue::delete_all+0x10a (compileBroker.cpp:373) V [jvm.dll+0x600ae0] CompileBroker::shutdown_compiler_runtime+0x70 (compileBroker.cpp:1835) V [jvm.dll+0x5fc196] CompileBroker::init_compiler_runtime+0x196 (compileBroker.cpp:1786) V [jvm.dll+0x5fa6c2] CompileBroker::compiler_thread_loop+0x132 (compileBroker.cpp:1920) V [jvm.dll+0x959e16] JavaThread::thread_main_inner+0x296 (javaThread.cpp:774) V [jvm.dll+0x11beaf4] Thread::call_run+0x1b4 (thread.cpp:248) V [jvm.dll+0xe37461] thread_native_entry+0xe1 (os_windows.cpp:562) C [ucrtbase.dll+0x2268a] (no source info available) C [KERNEL32.DLL+0x17ac4] (no source info available) C [ntdll.dll+0x5a8c1] (no source info available) Registers: RAX=0x00000282b7c30000, RBX=0x00000282c97f0640, RCX=0x00000282c97f0640, RDX=0x00007ff9d939987c RSP=0x000000fa69ffef90, RBP=0x000000fa69fff800, RSI=0x00000282c97f0630, RDI=0x00000282c97f0640 R8 =0x0000000000000000, R9 =0x00000282b7626440, R10=0x0000000000000000, R11=0x000000fa69ffec01 R12=0x0000000000000048, R13=0x00000282c97c6070, R14=0x00007ff9d98d96c8, R15=0x00000282c97c6070 RIP=0x00007ff9d8beb28a, EFLAGS=0x0000000000010206 the backtrace looks a bit like it could have to do with your change, any ideas ? Should I open a separate JBS issue ?
11-07-2025

Changeset: a41d3507 Branch: master Author: Aleksey Shipilev <shade@openjdk.org> Date: 2025-07-09 14:49:20 +0000 URL: https://git.openjdk.org/jdk/commit/a41d35073ee6da0dde4dd731c1ab4c25245d075a
09-07-2025

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/25409 Date: 2025-05-23 09:42:17 +0000
23-05-2025