Ответ 1
Проблема в том, что free
просто указывает сборщику мусора, что теперь он может собирать строку. На самом деле это не заставляет сборщик мусора работать - это просто указывает, что CString теперь мусор. По-прежнему ГК решает, когда запускать, исходя из эвристики давления кучи.
Вы можете принудительно создать основную коллекцию, вызвав performGC
прямо после вызова free
, что сразу уменьшит память до 5M или около того.
например. эта программа:
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)
Ведет себя так, как ожидалось, со следующим профилем памяти - первая красная точка - это вызов performGC
, немедленно освобождающий строку. Затем программа останавливается примерно на 5 м до тех пор, пока не прекратится.