Haskell DLL导致内存泄漏

Haskell DLL causes memory leak

我正在开发一个使用 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

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

我做错了什么?

P.S.进一步调查发现只有当HaskellExport.hs包含至少一个foreign export函数时才会导致内存泄漏。

我决定向 ghc-devs 邮件列表发送一封电子邮件。 (要阅读所有通信,请参阅 the question and further messages, the answer can be found here)。

简要说明。内存泄漏是由于以下原因造成的:对于每个外部导出,RTS 创建一个静态 C 包装器,它在 DLL_PROCESS_ATTACH 上初始化,但在 DLL_PROCESS_DETACH 期间没有要调用的 finalizer/destructor。所以它会一直存活到程序终止。