ghc-heap-view- Extract the heap representation of Haskell values and thunks

MaintainerJoachim Breitner <>
Safe HaskellNone




With this module, you can investigate the heap representation of Haskell values, i.e. to investigate sharing and lazy evaluation.


Heap data types

data GenClosure b Source

This is the main data type of this module, representing a Haskell value on the heap. This reflects

The data type is parametrized by the type to store references in, which should be either Box or WeakBox, with appropriate type synonyms Closure and WeakClosure.

allPtrs :: GenClosure b -> [b]Source

For generic code, this function returns all referenced closures.

data StgInfoTable Source

This is a somewhat faithful representation of an info table. See for more details on this data structure. Note that the Storable instance provided here does _not_ support writing.



Reading from the heap

getClosureData :: a -> IO ClosureSource

This function returns parsed heap representation of the argument _at this moment_, even if it is unevaluated or an indirection or other exotic stuff. Beware when passing something to this function, the same caveats as for asBox apply.

getBoxedClosureData :: Box -> IO ClosureSource

Like getClosureData, but taking a Box, so it is easier to work with.

getClosureRaw :: a -> IO (Ptr StgInfoTable, [Word], [Box])Source

This returns the raw representation of the given argument. The second component of the triple are the words on the heap, and the third component are those words that are actually pointers. Once back in Haskell word, the Word may be outdated after a garbage collector run, but the corresponding Box will still point to the correct value.

Pretty printing

ppClosure :: (Int -> b -> String) -> Int -> GenClosure b -> StringSource

A pretty-printer that tries to generate valid Haskell for evalutated data. It assumes that for the included boxes, you already replaced them by Strings using map or, if you need to do IO, mapM.

The parameter gives the precedendence, to avoid avoidable parenthesises.

Heap maps

For more global views of the heap, you can use heap maps. These come in variations, either a trees or as graphs, depending on whether you want to detect cycles and sharing or not.

data HeapTree Source

Heap maps as tree, i.e. no sharing, no cycles.

buildHeapTree :: Int -> Box -> IO HeapTreeSource

Constructing an HeapTree from a boxed value. It takes a depth parameter that prevents it from running ad infinitum for cyclic or infinite structures.

ppHeapTree :: HeapTree -> StringSource

Pretty-Printing a heap Tree

Example output for [Just 4, Nothing, *something*], where *something* is an unevaluated expression depending on the command line argument.

[Just (I# 4),Nothing,Just (_thunk ["arg1","arg2"])]

data HeapGraphEntry Source

For heap graphs, i.e. data structures that also represent sharing and cyclic structures, these are the entries. If the referenced value is Nothing, then we do not have that value in the map, most likely due to exceeding the recursion bound passed to buildHeapGraph.


newtype HeapGraph Source

The whole graph. The suggested interface is to only use lookupHeapGraph, as the internal representation may change. Nevertheless, we export it here: Sometimes the user knows better what he needs than we do.


buildHeapGraph :: Int -> Box -> IO HeapGraphSource

Creates a HeapGraph for the value in the box, but not recursing further than the given limit. The initial value has index heapGraphRoot.

ppHeapGraph :: HeapGraph -> StringSource

Pretty-prints a HeapGraph. The resulting string contains newlines. Example for let s = Ki in (s, s, cycle Ho):

let x1 = "Ki"
    x6 = C# 'H' : C# 'o' : x6
in (x1,x1,x6)


data Box Source

An arbitrarily Haskell value in a safe Box. The point is that even unevaluated thunks can safely be moved around inside the Box, and when required, e.g. in getBoxedClosureData, the function knows how far it has to evalue the argument.


Box Any 


asBox :: a -> BoxSource

This takes an arbitrary value and puts it into a box. Note that calls like

 asBox (head list) 

will put the thunk "head list" into the box, not the element at the head of the list. For that, use careful case expressions:

 case list of x:_ -> asBox x

Weak boxes

data WeakBox Source

An a variant of Box that does not keep the value alive.

Like Box, its Show instance is highly unsafe.


weakBox :: Box -> IO WeakBoxSource

Turns a Box into a WeakBox, allowing the referenced value to be garbage collected.

isAlive :: WeakBox -> IO BoolSource

Checks whether the value referenced by a weak box is still alive

derefWeakBox :: WeakBox -> IO (Maybe Box)Source

Dereferences the weak box