All posts

Fix Memory Leak in Haskell

Resolve memory leaks in Haskell caused by lazy evaluation, unevaluated thunks, and space leaks in common data structures.

Space Leaks in Haskell

Haskell's lazy evaluation is powerful but introduces a unique class of memory leaks called "space leaks" — unevaluated thunks accumulate in memory, using far more space than the actual computed values would.

The Classic foldl Leak

-- BAD — builds a huge thunk chain
total = foldl (+) 0 [1..10000000]
-- Creates: ((((0 + 1) + 2) + 3) + ...)
-- None of these additions are evaluated!

-- GOOD — strict left fold
total = foldl' (+) 0 [1..10000000]
-- Evaluates each addition immediately

Always import Data.List (foldl') and use the strict version.

Lazy Fields in Data Types

-- BAD — lazy fields accumulate thunks
data Stats = Stats
  { count :: Int
  , total :: Double
  }

-- GOOD — strict fields with BangPatterns
{-# LANGUAGE StrictData #-}
data Stats = Stats
  { count :: !Int
  , total :: !Double
  }

Accumulator Pattern

-- BAD — lazy accumulator
process [] acc = acc
process (x:xs) acc = process xs (acc + compute x)

-- GOOD — force the accumulator with seq
process [] acc = acc
process (x:xs) acc = let acc' = acc + compute x
                     in acc' `seq` process xs acc'

Finding Leaks

Compile with profiling and use heap profiles:

ghc -O2 -prof -fprof-auto -rtsopts Main.hs
./Main +RTS -hc -p
hp2ps Main.hp

This generates a visual heap profile showing which cost centres consume the most memory.

Bugsly can receive memory metrics from Haskell services via its API, helping you track space leaks in production before they cause outages.

Try Bugsly Free

AI-powered error tracking that explains your bugs. Set up in 2 minutes, free forever for small projects.

Get Started Free