From 1a776d117fb9b81b76c8d90578da2546414f3f5f Mon Sep 17 00:00:00 2001 From: Timur Mustafin Date: Mon, 26 Jan 2026 08:18:33 +0300 Subject: [PATCH 1/4] Fix crossgen2 nobubble memleak --out-near-input and --single-file-compilation options without inputbubble option leads to memory leak. Co-authored-by: Dong-Heon Jung --- .../ReadyToRun/ManifestMetadataTableNode.cs | 7 ++++++- .../Compiler/ReadyToRunCodegenCompilation.cs | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs index a021c4c83fd93d..525952ee5f1920 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs @@ -27,7 +27,7 @@ public interface ISignatureEmitter void MaterializeSignature(); } - public class ManifestMetadataTableNode : HeaderTableNode + public class ManifestMetadataTableNode : HeaderTableNode, IDisposable { /// /// Map from simple assembly names to their module indices. The map gets prepopulated @@ -329,5 +329,10 @@ internal byte[] GetManifestAssemblyMvidTableData() } return manifestAssemblyMvidTable; } + + public void Dispose() + { + _modulesWhichMustBeIndexable.Clear(); + } } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs index 6f29c1ef8bdb8b..332a0dd10ba6c2 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs @@ -1022,6 +1022,7 @@ public ISymbolNode GetFieldRvaData(FieldDesc field) public override void Dispose() { + _nodeFactory.ManifestMetadataTable.Dispose(); Array.Clear(_corInfoImpls); } From d2453f180a0714686abad61cf713ff884bc28b69 Mon Sep 17 00:00:00 2001 From: Timur Mustafin Date: Mon, 2 Feb 2026 16:57:16 +0300 Subject: [PATCH 2/4] Feedback --- .../DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs | 2 +- .../Compiler/ReadyToRunCodegenCompilation.cs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs index 525952ee5f1920..26ac359f10f6ec 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/ManifestMetadataTableNode.cs @@ -332,7 +332,7 @@ internal byte[] GetManifestAssemblyMvidTableData() public void Dispose() { - _modulesWhichMustBeIndexable.Clear(); + _modulesWhichMustBeIndexable = null; } } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs index 332a0dd10ba6c2..48dc4b1b6bd8a2 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs @@ -1022,7 +1022,9 @@ public ISymbolNode GetFieldRvaData(FieldDesc field) public override void Dispose() { + // Workaround for https://github.com/dotnet/runtime/issues/23103 _nodeFactory.ManifestMetadataTable.Dispose(); + // Workaround for https://github.com/dotnet/runtime/issues/12255 Array.Clear(_corInfoImpls); } From be1dcb5948659c564b6e5d367d28b1c6d5b1d3db Mon Sep 17 00:00:00 2001 From: Timur Mustafin Date: Mon, 2 Feb 2026 17:18:15 +0300 Subject: [PATCH 3/4] Feedback --- .../Compiler/ReadyToRunCodegenCompilation.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs index 48dc4b1b6bd8a2..b467709f48fb45 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs @@ -1022,9 +1022,16 @@ public ISymbolNode GetFieldRvaData(FieldDesc field) public override void Dispose() { - // Workaround for https://github.com/dotnet/runtime/issues/23103 + // Workaround for https://github.com/dotnet/runtime/issues/23103. + // ManifestMetadataTable.Dispose() allows to break circular reference + // ConcurrentBag -> EcmaModule -> EcmaAssembly -> ReadyToRunCompilerContext -> ... -> ConcurrentBag. + // This circular reference along with #23103 prevents objects from being collected by GC. _nodeFactory.ManifestMetadataTable.Dispose(); - // Workaround for https://github.com/dotnet/runtime/issues/12255 + + // Workaround for https://github.com/dotnet/runtime/issues/12255. + // Array.Clear(_corInfoImpls) allows to break circular reference + // ConditionalWeakTable _corInfoImpls -> ReadyToRunCodegenCompilation _compilation -> ConditionalWeakTable _corInfoImpls. + // This circular reference along with 12255 prevents objects from being collected by GC. Array.Clear(_corInfoImpls); } From 562a32517279c3d6a712195af474d81f64e8b549 Mon Sep 17 00:00:00 2001 From: Timur Mustafin Date: Tue, 3 Feb 2026 01:47:04 +0300 Subject: [PATCH 4/4] Do not force clean _corInfoImpls cause it is not ConditionalWeakTable --- .../Compiler/ReadyToRunCodegenCompilation.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs index b467709f48fb45..9194609418f4ab 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs @@ -1027,12 +1027,6 @@ public override void Dispose() // ConcurrentBag -> EcmaModule -> EcmaAssembly -> ReadyToRunCompilerContext -> ... -> ConcurrentBag. // This circular reference along with #23103 prevents objects from being collected by GC. _nodeFactory.ManifestMetadataTable.Dispose(); - - // Workaround for https://github.com/dotnet/runtime/issues/12255. - // Array.Clear(_corInfoImpls) allows to break circular reference - // ConditionalWeakTable _corInfoImpls -> ReadyToRunCodegenCompilation _compilation -> ConditionalWeakTable _corInfoImpls. - // This circular reference along with 12255 prevents objects from being collected by GC. - Array.Clear(_corInfoImpls); } public string GetReproInstructions(MethodDesc method)