首页 > 解决方案 > 启动dll时C#环境堆栈溢出

问题描述

我有一个加载 dll 函数的 C# 程序:

[DllImport("/Users/frk/Workspaces/MySharedLibrary.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto, EntryPoint = "MyCFunction")]

public static extern int MyFunction( [In][MarshalAs(UnmanagedType.I4)]MyFormat format,  [In][MarshalAs(UnmanagedType.LPArray)] byte[] myString,  [In][MarshalAs(UnmanagedType.I4)] int myStringLength, [MarshalAs(UnmanagedType.LPArray)] byte[] output,  ref UIntPtr outputLength);

并称它为

int result = MyFunction(format, inPut, inputLength, outPut, ref outputLength);

在 C++ 方面,我有:

当从 C 测试可执行文件调用时,MyCPPFunction 可以完美运行。MyCPPFunction 在其依赖关系的深处包含一个在匿名命名空间中声明和初始化的全局 const 变量:

namespace
{
        constexpr unsigned RandTileSize = 256;

        std::array<unsigned, RandTileSize * RandTileSize> GenerateSamples()
        {
            std::array<unsigned, RandTileSize * RandTileSize> samples;

            std::mt19937 rd(0);
            std::uniform_int_distribution<unsigned> distribution(0, 255);

            for (unsigned i = 0; i < RandTileSize * RandTileSize; ++i)
            {
                samples[i] = distribution(rd);
            }

            return samples;
        };

        const auto samples = GenerateSamples();<-- Option#1 this causes a stack overflow when loading the dll in C# environment

        unsigned Sample(unsigned index)
        {
               static const auto samples = GenerateSamples();<-- Option#2 this works and dll loads correctly
               return samples[index];
        }
}

我在这里很困惑,因为 afaik,选项 1 应该在 dll 的代码部分分配内存,C# 环境应该处理对吗?

我们如何才能在加载 dll 时选择 #1 不导致内存分配问题?

标签: c#c++interface

解决方案


DLL 中函数中静态变量的生命周期是从第一次遇到语句到 DLL 卸载的时间。

类或文件范围变量的生命周期是从 DLL 加载到 DLL 卸载。

这样做的结果是,在失败的情况下,您的初始化代码正在运行,而 DLL 正在加载.

在类构造函数中运行重要的代码通常不是一个好主意,因为在加载器锁内可以安全地完成的事情是有限制的。

特别是如果您执行任何需要动态加载另一个 DLL 的操作(例如LoadLibrary或调用延迟加载链接函数),这可能会导致难以诊断的问题。

如果不准确诊断您的情况出了什么问题,答案很简单:使用选项 2 或选项 3。

选项 3:

void MyDLLInitialize(){
    // Initialize the dll here
}

void MyDLLUninitialize(){
   // Uninitialize the dll here
}

然后分别在使用任何其他 DLL 函数之前和完成之后从 C# 调用这些函数。


推荐阅读