【发布时间】:2017-04-13 15:26:45
【问题描述】:
我正在学习如何使用 Haskell 的 C FFI。
假设我正在调用一个 C 函数,它创建一个对象,然后返回一个指向该对象的指针。我是否可以使用free 从 Haskell 运行时释放此内存?
(我指的是 Haskell 的free不是 C 的free)
考虑以下代码:
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
import Prelude hiding (exp)
import Foreign.Marshal.Alloc
import Foreign.Storable
import Foreign.C.Types
import Foreign.Ptr
import Foreign.Marshal.Array
foreign import ccall "get_non_freed_array" c_get_non_freed_array :: CInt -> IO (Ptr CInt) -- An array initialized
main :: IO()
main = do
let numelements = 5
ptr <- c_get_non_freed_array numelements
w0 <- peek $ advancePtr ptr 0
w1 <- peek $ advancePtr ptr 1
w2 <- peek $ advancePtr ptr 2
w3 <- peek $ advancePtr ptr 3
w4 <- peek $ advancePtr ptr 4
print [w0, w1, w2, w3, w4]
return ()
我用C99写的get_non_freed_array函数如下
#include "test.h"
#include <stdlib.h>
// return a memory block that is not freed.
int* get_non_freed_array(int n)
{
int* ptr = (int*) malloc(sizeof(int)*n);
for(int i=0 ; i<n ; ++i){
ptr[i] = i*i;
}
return ptr;
}
(test.h 只包含一行包含get_non_freed_array 的函数签名,供 Haskell 的 FFI 访问它。)
我很困惑,因为当从 Haskell 的运行时调用 C 函数“完成”运行后,我不知道 C 运行时分配的内存是否被垃圾回收。我的意思是,如果是另一个 C 函数调用它,那么我知道内存可以安全使用,但是由于 Haskell 函数正在调用 get_non_freed_array,我不知道这是不是真的了。
即使上面的 Haskell 代码打印出正确的结果,我也不知道 C 函数返回的内存是否可以通过 ptr 安全使用。
如果它是安全的,我们可以从 Haskell 本身中释放这段内存吗?还是我必须在 test.c 中编写另一个 C 函数,例如 destroy_array(int* ptr),然后从 Haskell 调用它?
编辑: 简而言之,我需要更多关于在 Haskell 中编写代码时如何使用指向在 C 函数中创建的对象的指针的信息。
【问题讨论】:
-
你指的是哪个 Haskell
free?你有文档参考吗? Etit:NVM,它是downloads.haskell.org/~ghc/8.0.1-rc2/docs/html/libraries/… -
我猜它不安全,因为 C 和 Haskell 的分配算法可能不同。但是你可以试试,如果你幸运的话,你会得到一些分段错误,知道你不能这样做。
-
您应该只使用与分配器用户匹配的空闲空间来分配内存。即使没有跨越语言障碍,这也适用。 C 中的不同库可以使用不同的分配器。您需要为所有内容使用正确的免费功能。
-
回答你的最后一个问题(
destroy_array):这是一个安全的解决方案,是的。另一种方法是使用alloca(或mallocArray,如果您不希望内存由GHC管理)在Haskell中进行分配,并将指向已分配内存的指针传递给您的C函数(之后将其从Haskell中释放)在mallocArray情况下;在allocaArray情况下,您无需再做任何事情)。我经常发现这种方法比在 C 端分配/释放更整洁。
标签: c haskell garbage-collection