2012-05-09 3 views
10

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

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 программа показала, что использование памяти где-то около 410м - это нормально. Я нажимаю enter, и программа останавливается на линии (2), но использование памяти по-прежнему составляет 410M, несмотря на то, что cs был free d!

Как это возможно? Подобная программа, написанная на C, ведет себя так, как должна. Что мне здесь не хватает?

+1

Какая версия GHC вы используете? Возможность вернуть память в ОС была добавлена ​​только в GHC в прошлом году. –

+0

'ghc --version' выходы' Славная система компиляции Haskell Glasgow, версия 7.4.1' –

ответ

8

Проблема заключается в том, что free просто указывает сборщику мусора, что теперь он может собирать строку. На самом деле это не заставляет сборщик мусора работать - это просто указывает, что CString теперь мусор. По-прежнему до ГК решать, когда запускать, на основе эвристики давления кучи.

Вы можете сила главным коллекция по телефону performGC сразу после вызова free, что сразу снижает память к 5М или около того.

E.g. эта программа:

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, немедленно deallocating строку. Затем программа опускается примерно на 5M до тех пор, пока она не прекратится.

enter image description here

+0

Большое спасибо. Я не знал, что 'malloc' /' free' в ghc работают таким образом. Я попробовал 'performGC', и он действительно работает. Ну, этот вопрос возник, когда я тестировал, насколько хорошо мои привязки к определенной библиотеке C работают. Я тестировал их с большим количеством строк C и с удивлением обнаружил, что память не выпускается. Кажется, эта тайна решена сейчас) –

+2

Думаю, я не могу спорить с вашими доказательствами, что 'performGC' действительно работает, но это то, что я предположил, был ответом, пока я не пошел и не посмотрел на [источник] (http: // hackage.haskell.org/packages/archive/base/4.5.0.0/doc/html/src/Foreign-Marshal-Alloc.html#free) - мне кажется, что 'free' действительно вызывает функцию C' free (free)) '. Как это взаимодействует с GC? –

+2

Я подозреваю, что это потому, что память фактически не выпущена ОС из пула GHC rts до тех пор, пока GC не запустится. Таким образом, вы сможете повторно использовать блок памяти из Haskell, но он еще не возвращается обратно в ОС. –

Смежные вопросы