我正在使用一个使用
Haskell DLL的C项目(GHC版本是8.0.1 x64).我注意到,执行程序消耗了大量内存.我调查了这件事,这就是我发现的.让我们考虑以下最小的例子.这是一个由三个文件组成的小项目.
HaskellExports.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module HaskellExports where
import Foreign.C.Types
import Foreign.StablePtr
foreign export ccall foo :: CInt -> IO (StablePtr Int)
foo :: CInt -> IO (StablePtr Int)
foo (CInt n) = newStablePtr (fromIntegral n)
包含一个应该从C/C++代码调用的函数.
CWrapper.cpp
#define DLLExport extern "C" __declspec(dllexport)
DLLExport void* c_smth (const int num)
{
return 0;
}
我故意没有包含Haskell函数的实际导出,因为它们对这个例子没有任何影响.
main.cpp中
#include <Windows.h>
int main()
{
for (;;)
{
HINSTANCE module = ::LoadLibrary(L"HaskellExports.dll");
::FreeLibrary(module);
}
return 0;
}
在这里,在无限循环中,我加载库并立即释放它.让我们尝试以两种不同的方式构建DLL.首先,我们不要包含Haskell对象文件:
ghc -c HaskellExports.hs
ghc -c CWrapper.cpp
ghc -shared -no-hs-main -o HaskellExports.dll CWrapper.o
我运行该程序并注意到(在Windows进程监视器的帮助下),内存资源被正确捕获和释放.
现在让我们添加Haskell对象文件:
ghc -c HaskellExports.hs
ghc -c CWrapper.cpp
ghc -shared -no-hs-main -o HaskellExports.dll CWrapper.o HaskellExports.o
我再次运行该程序并注意到,它在很长一段时间内消耗了越来越多的内存而无意释放它.这种情况导致崩溃.
我究竟做错了什么?
附:进一步的调查表明,只有当HaskellExport.hs包含至少一个外部导出函数时才会导致内存泄漏.
最佳答案 我决定发电子邮件到ghc-devs邮件列表. (要阅读所有通信,请参阅
the question和更多消息,答案可以在
here找到).
简要说明.内存泄漏是由于以下原因引起的:对于每个外部导出,RTS创建一个静态C包装器,它在DLL_PROCESS_ATTACH上初始化,但在DLL_PROCESS_DETACH期间没有终结器/析构函数.所以它会一直存在,直到程序终止.