10

正如库文档所说CString,创建的newCString必须使用free函数释放。我一直期待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 左右——这没关系。我按回车,程序在第 (2) 行停止,但内存使用量仍然是 410M,尽管cs已经freed!

这怎么可能?用 C 编写的类似程序的行为应如此。我在这里想念什么?

4

1 回答 1

8

问题是它free只是向垃圾收集器表明它现在可以收集字符串。这实际上并没有强制垃圾收集器运行——它只是表明 CString 现在是垃圾。仍然由 GC 根据堆压力启发式决定何时运行。

您可以通过在调用 to 之后直接调用来强制进行主要收集,这会立即将内存减少到 5M 左右。performGCfree

例如这个程序:

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 左右徘徊直到终止。

在此处输入图像描述

于 2012-05-09T12:50:56.923 回答