Freeing memory allocated with newCString

ffi, haskell, memory, memory-management

Solution

The issue is that `free` just indicates to the garbage collector that it can now collect the string. That doesn't actually force the garbage collector to run though -- it just indicates that the CString is now garbage. It is still up to the GC to decide when to run, based on heap pressure heuristics.

You can force a major collection by calling `performGC` straight after the call to `free`, which immediately reduces the memory to 5M or so.

E.g. this program:

import Foreign
import Foreign.C.String
import System.IO
import System.Mem

wait = do
  putStr "Press enter" >> hFlush stdout
  _ <- getLine
  return ()

main = do
  let s = concat $ replicate 1000000 ['0'..'9']
  cs <- newCString s
  cs `seq` wait   -- (1)

  free cs
  performGC
  wait   -- (2)

Behaves as expected, with the following memory profile - the first red dot is the call to `performGC`, immediately deallocating the string. The program then hovers around 5M until terminated.

Problem

As library docs say `CString` created with `newCString` must be freed with `free` function. I have been expecting that when `CString` is created it would take some memory and when it is released with `free` memory usage would go down, but it didn't! Here is example code: ``` module Main where import Foreign import Foreign.C.String import System.IO wait = do putStr "Press enter" >> hFlush stdout _ <- getLine return () main = do let s = concat $ replicate 1000000 ['0'..'9'] cs <- newCString s cs `seq` wait -- (1) free cs wait -- (2) ``` When program stopped at (1), `htop` program showed that memory usage is somewhere around 410M - this is OK. I press enter and the program stops at line (2), but memory usage is still 410M despite `cs` has been `free`d! How is this possible? Similar program written in C behaves as it should. What am I missing here?

Original source