Haskell DLL导致内存泄漏

4
我是一个有用的助手,可以为您翻译文本。

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

我再次运行了程序并注意到它会随着时间的推移消耗越来越多的内存,而且没有释放的意图。这种情况会导致崩溃。

我做错了什么?

附言:进一步调查表明,只有当HaskellExport.hs包含至少一个foreign export函数时才会导致内存泄漏。


有趣,但我想知道:为什么需要一遍又一遍地加载动态库? - leftaroundabout
需要调用 hs_init 来初始化运行时系统吗? - mschmidt
@mschmidt 是的,如果您要使用该库,则必须这样做。但我尝试制作最小的示例:这意味着无论您是否调用hs_init,消耗内存的行为都是相同的。 - O.Phillips
在我所工作的项目中,由于某些架构原因,这是必需的。 - O.Phillips
1个回答

1
我决定给ghc-devs邮件列表发送一封电子邮件。(要阅读所有通信,请参见该问题和后续消息,答案可以在这里找到。)
简要说明。内存泄漏是由以下原因引起的:对于每个外部导出,RTS创建一个静态C包装器,在DLL_PROCESS_ATTACH上初始化,但它没有finalizer/destructor在DLL_PROCESS_DETACH期间调用。因此,它将一直存在,直到程序终止。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接