Освобождение памяти, выделенной с помощью newCString

как говорят библиотечные документы CString создано с помощью newCString должен быть освобожден с . Я ожидал этого, когда CString создается, это займет некоторую память, и когда она будет выпущена с free использование памяти снизится, но это не так! Вот пример кода:

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)

когда программа остановилась на (1), htop программа показала, что использование памяти где - то около 410M-это нормально. Я нажимаю enter, и программа останавливается на строке (2) , но использование памяти все еще Несмотря на 410 м cs была freed!

как это возможно? Аналогичная программа, написанная на C ведет себя как надо. Я что-то упускаю?

1 ответов


проблема в том, что free просто указывает сборщику мусора, что теперь он может собирать строку. Это на самом деле не заставляет сборщик мусора работать, хотя-это просто указывает на то, что CString теперь мусор. Это все еще до GC, чтобы решить, когда запускать, на основе эвристики давления кучи.

вы можете силу основная коллекция по телефону 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, немедленно освобождая строку. Затем программа зависает вокруг 5M до завершения.

enter image description here