Testcase: ----- import core.memory; import core.stdc.stdio; import std.range; import std.format; int toMB(ulong size) { return cast(int) (size / 1048576.0 + 0.5); } void printGCStats() { const stats = GC.stats; const used = toMB(stats.usedSize); const free = toMB(stats.freeSize); const total = toMB(stats.usedSize + stats.freeSize); printf(" GC stats: %dM used, %dM free, %dM total\n", used, free, total); } void formatRange() { string str = format("%s", iota(100_000_000)); printf(" string size: %dM\n", toMB(str.length)); } void main() { printGCStats(); while (true) { puts("Starting"); formatRange(); GC.collect(); printGCStats(); } } ----- On Windows, with DMD 2.092: > dmd -m64 test.d > test.exe GC stats: 0M used, 1M free, 1M total Starting string size: 943M GC stats: 1168M used, 1139M free, 2306M total Starting string size: 943M GC stats: 1168M used, 2456M free, 3623M total Starting string size: 943M GC stats: 1168M used, 2456M free, 3623M total Starting string size: 943M GC stats: 1168M used, 2456M free, 3623M total Starting string size: 943M GC stats: 1168M used, 2456M free, 3623M total ... The expected behavior is that there should be no used GC memory after an iteration - the huge string is built in another function and doesn't escape, and the manual collection should mark all memory as being unused. Using the precise GC via `test.exe --DRT-gcopt=gc:precise` makes no difference. No idea whether that's a GC issue (druntime) or std.format doing weird things.
Seems to be GC-specific, as it also happens for a huge linked list, see https://forum.dlang.org/post/mkcpimoomnlnrruelbkh@forum.dlang.org (yes, even when extracting the actual work and `dll` ref on the stack into a dedicated function).
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/17406 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB