Haskell DLL导致内存泄漏

时间:2018-08-24 13:19:48

标签: haskell dll memory-leaks ghc ffi

我正在使用Haskell DLL(GHC版本是8.0.1 x64)的C ++项目中工作。我注意到,正在执行的程序会消耗大量内存。我对此事进行了调查,这就是我所发现的。让我们考虑以下最小示例。这是一个由三个文件组成的小项目。

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

我再次运行该程序并注意到,它在无意释放它的时间长度上消耗了越来越多的内存。这种情况会导致崩溃。

我在做什么错了?

P.S。。进一步的调查表明,仅当HaskellExport.hs包含至少一个foreign export函数时才会引起内存泄漏。

1 个答案:

答案 0 :(得分:1)

我决定向ghc-devs邮件列表发送一封电子邮件。 (要阅读所有信件,请参阅the question和其他消息,答案here中可以找到。)

简要说明。内存泄漏是由以下原因引起的:对于每个外部导出,RTS都会创建一个静态C包装器,该包装器在DLL_PROCESS_ATTACH上初始化,但是在DLL_PROCESS_DETACH期间没有终结器/析构函数被调用。因此它将一直存在,直到程序终止。