Guide
Diagnosing and Fixing Space Leaks in Haskell Programs
Identify growing memory footprints, profile thunk accumulation with GHC, and apply targeted strictness fixes.
Published by Tasadduq Burney
22 Aug 2025, 18:09 UTC
3 min52.4K views0

Recognizable Condition
During execution the resident memory (RSS) or heap size grows steadily while CPU usage remains low. The program may slow down or be terminated by an OOM limit despite minimal computation.
Cause and Diagnostic Table
| Common cause | What to look for in a profile |
|---|---|
| Unevaluated thunks in lazy data structures (lists, maps) | Large retained size attributed to THUNK or CONSTR nodes in the heap profile |
| Lazy accumulation in a fold or scan | Cost centre showing the fold function with increasing THUNK retention |
| Large lazy I/O buffers (e.g., getContents) | Retained size in I/O related cost centres, often with many CONSTR of ByteString chunks |
Ordered Checks
- Recompile with profiling support:
ghc -prof -fprof-auto -rtsopts Program.hs -o Program. Requires source write access and GHC invocation. - Run with runtime flags:
./Program +RTS -p -hy. The-pflag generates a time/allocation report (.prof);-hyproduces a heap profile by closure type (.hp. - Examine
.proffor cost centres with high allocation or time. Identify entries labelledTHUNKorCONSTRretaining large memory fractions. - If a growing retained set appears in the heap profile, use
hp2ps Program.hpfor a PostScript graph orhp2prettyfor interactive viewing. Identify the cost centre with the largest band.
Fixes Tied to Findings
- Replace a hot spot
foldlwith the strict versionData.List.foldl'or add a bang pattern:foldl' (\acc x -> acc + x) 0 xs. - For lazy maps that build thunks, switch to
Data.Map.Strictor insertseq/bang patterns at update sites. - When large lazy I/O is the cause, replace
getContentsorhGetContentswith strict reads fromData.ByteString(ByteString.hGet) orData.Text.IO. - Add explicit strictness annotations where profiling indicates thunk buildup, using
BangPatterns(!x) orseqto force evaluation at accumulation points.
Escalation Criteria
- If the heap profile shows no large THUNK/CONSTR retention but memory still grows, consider runtime system bugs, foreign memory leaks (C FFI), or excessive thread stacking. Check with
+RTS -sfor GC stats and thread counts. - Enable detailed GC statistics:
./Program +RTS -sand look for increasingtotal memory in useor highGC time. - Consult GHC Trac or mailing lists, providing the
.prof,.hp, and GC output for further analysis.
Verification
- Re-run the program with the same profiling flags after applying a fix.
- Confirm the heap profile no longer exhibits a large retained band for the previously suspect cost centre.
- Check that RSS or heap size remains bounded across varied input sizes matching production workloads.
- Ensure the test suite passes and performance benchmarks show no regression; if performance degrades, re-evaluate strictness placement.
Note: Over-strictness can remove laziness benefits and may cause stack overflows; apply strictness only where profiling indicates a thunk buildup, and verify semantics after each change.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.