2012-05-09 87 views
10

由于库文档说与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程序显示内存使用某处大约410M - 这是确定。我按回车,程序停在第(2)行,但内存使用仍然是410M,尽管cs已经free d!

这怎么可能?用C编写的类似程序的行为应该与它应该一样。我在这里错过了什么?

+1

您正在使用哪个版本的GHC?将内存返回到操作系统的能力仅在去年被添加到GHC中。 –

+0

'ghc --version'输出'Glorious Glasgow Haskell编译系统,版本7.4.1' –

回答

8

问题是free只是告诉垃圾收集器它现在可以收集字符串。这实际上并没有强制垃圾收集器运行 - 它只是表明CString现在是垃圾。基于堆压力启发式,决定何时运行取决于GC。

您可以通过调用free,立即降低了内存为5M左右后直接调用performGC一大集合。

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,立即重新分配的字符串。该程序然后徘徊在5M左右直到终止。

enter image description here

+0

非常感谢。我不知道ghc中的'malloc' /'free'这样工作。我试过'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( )'。这与GC有什么相互作用? –

+2

我怀疑是因为内存没有真正从GHC rts池释放到操作系统,直到GC运行。所以你可以重新使用Haskell的内存块,但它不会回馈给操作系统。 –