2012-05-09 13 views
10

Als Bibliotheksdokumente sagen CString erstellt mit newCString muss mit free Funktion freigegeben werden. Ich habe erwartet, dass, wenn CString erstellt wird, würde es einige Speicher benötigen und wenn es mit free freigegeben wird Speicherverbrauch würde sinken, aber es hat nicht! Es folgt ein Beispielcode:Freigeben von Speicher, der mit newCString belegt ist

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) 

Wenn das Programm hielt an (1), htop Programm zeigte, dass die Speichernutzung irgendwo um 410M ist - das ist OK. Ich drücke Enter und das Programm stoppt bei Zeile (2), aber Speicherverbrauch ist immer noch 410M trotz cs wurde free d!

Wie ist das möglich? Ein ähnliches in C geschriebenes Programm verhält sich wie es sollte. Was fehlt mir hier?

+1

Welche Version von GHC verwenden Sie? Die Möglichkeit, Speicher an das Betriebssystem zurückzugeben, wurde erst letztes Jahr zu GHC hinzugefügt. –

+0

'ghc --version' Ausgaben' The Glorious Glasgow Haskell Compilation System, Version 7.4.1' –

Antwort

8

Das Problem ist, dass free nur dem Garbage Collector anzeigt, dass es jetzt die Zeichenfolge sammeln kann. Das zwingt den Garbage Collector nicht tatsächlich dazu, auszuführen - es zeigt nur an, dass der CString jetzt unbrauchbar ist. Es ist immer noch Sache des GC, basierend auf heuristischen Druckheuristiken zu entscheiden, wann er ausgeführt werden soll.

Sie können Kraft eine große Sammlung von performGC direkt nach dem Aufruf free Aufruf, die sofort auf den Speicher 5M reduziert oder so.

z. dieses Programm:

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) 

verhält sich wie mit dem folgenden Speicher Profil erwartet - die erste rote Punkt ist der Aufruf performGC, sofort freigibt, die Zeichenfolge. Das Programm schwebt dann um 5M, bis es beendet wird.

enter image description here

+0

Vielen Dank. Ich wusste nicht, dass 'malloc' /' free' in ghc so funktioniert. Ich habe 'performGC' versucht und es funktioniert tatsächlich. Nun, diese Frage entstand, als ich testete, wie gut meine Bindungen an bestimmte C-Bibliotheken funktionieren. Ich testete sie mit einer großen Menge C-Saiten und war überrascht herauszufinden, dass die Erinnerung nicht freigab. Es scheint, dieses Geheimnis ist jetzt gelöst) –

+2

Ich denke, ich kann nicht mit Ihren Beweisen argumentieren, dass "performGC" wirklich funktioniert, aber das ist, was ich angenommen habe, war die Antwort, bis ich ging und schaute auf die [Quelle] (http: // hackage.haskell.org/packages/archive/base/4.5.0.0/doc/html/src/Foreign-Marshal-Alloc.html#free) - es sieht für mich so aus als würde "free" die C-Funktion 'free 'nennen () '. Wie wirkt sich das auf den GC aus? –

+2

Ich vermute, dass ist, weil der Speicher nicht tatsächlich aus dem GHC-rts-Pool für das Betriebssystem freigegeben wird, bis der GC ausgeführt wird. Sie können also den Speicherblock von Haskell wiederverwenden, es wird jedoch noch nicht an das Betriebssystem zurückgegeben. –

Verwandte Themen