Haskell DLL вызывает утечку памяти - PullRequest
0 голосов
/ 24 августа 2018

Я работаю над проектом C ++, в котором используется библиотека Haskell (версия 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 функцию.

1 Ответ

0 голосов
/ 28 августа 2018

Я решил отправить электронное письмо в список рассылки ghc-devs. (Чтобы прочитать всю переписку, см. вопрос и другие сообщения, ответ можно найти здесь ).

Краткое объяснение. Утечка памяти возникает из-за следующего: для каждого внешнего экспорта RTS создает статическую оболочку C, которая инициализируется на DLL_PROCESS_ATTACH, но у нее нет финализатора / деструктора, вызываемого во время DLL_PROCESS_DETACH. Так что он останется в живых до завершения программы.

...