如何获取 C# 不安全结构的 IntPtr 以释放其在 C++ dll 中初始化的内存

How to get IntPtr of c# unsafe struct to free its memory initialized in c++ dll

请告诉我如何使用一些标准 C# 工具集从创建的 unsafe C# struct(s) 中释放内存,或者如何获取这些对象的 IntPtr使用默认提供的自定义 C++ 库?

问题详情(UPD):

  1. 我创建了 C# unsafe struct 并将其传递给我无法更改的 C++ dll TH_ExtractBimTemplate(ref createdStruct)。 dll 更新其内容。除此之外,dll 将对内部结构对象的引用保存在内部列表中。这是结构定义:

    public unsafe struct BIM_Template 
    { 
        public ushort ImageSizeX; 
        public ushort ImageSizeY; 
        public fixed uint Mint[MAX_MINUTIAE_SIZE]; 
        public uint Reserve; 
    }
    
  2. 在 API 调用 return 之后,我在我的 C# 代码中使用由 C++ dll 填充的结构中的数据。

  3. 我需要释放结构和 C++ 使用的内存。该 dll 有一个 API 来执行此操作,TH_FreeMemory.

对于第 3 步,我需要将对象引用(我假设 IntPtr)传递给 C++ 库,或者我需要释放它使用某些 C# 工具占用的内存。

即使在我的 C# 代码中没有对对象的引用,垃圾收集也不起作用,我假设,因为结构对象引用存储在我无法控制的 dll 的列表中。当调用结构对象上的 TH_FreeMemory 时,它将它从列表中删除并使用 delete 释放内存,但我无法生成 C# IntPtr 以将其传递给 TH_FreeMemory 因为...

我该怎么做 - 仅使用 C# 工具释放内存,忽略列表 dll 或为此结构生成 IntPtr

实现细节:

这是我创建和初始化它的方式:

BIM_Template template = default;
var template = TH_ExtractBimTemplate(ref template)

其中TH_ExtractBimTemplate(...)是这样从C++ dll中拉取的方法:

[DllImport("TemplateHelper.dll")]
private static extern int TH_ExtractBimTemplate(
ref BIM_Template out_template);

TemplateHelper.dll 提供了一个释放内存的 C++ 方法 - TH_FreeMemory:

int WINAPI TH_FreeMemory( void *memblock,  BIM_MemBlockType memblock_type )

这就是我将其插入 C# 的方式

[DllImport("TemplateHelper.dll")]
    private static extern int TH_FreeMemory(
    IntPtr memblock, BIM_MemBlockType memblock_type
); 

我目前尝试的解决方案:

[Fact]
public void TestDisposalIsCalledOnOutOfContext()
{
    // Create templates
    var templates = LoadTemplates(m, Output);
    // Release the allocated memory using Marshal 
    templates.ForEach( t => MarshaFreeMemory(ref t));
    // Wait
    Thread.Sleep(new TimeSpan(hours: 1, 0, 0)); 
}

private static IntPtr MarshaFreeMemory(ref BIM_Template? template) 
{
    IntPtr ptr;
    ptr = Marshal.AllocHGlobal(Marshal.SizeOf<BIM_Template>()); 
    Marshal.StructureToPtr(template, ptr, true);
    Marshal.FreeHGlobal(ptr);
    
    return ptr;
}
private static List<BIM_Template?> LoadTemplates() 
{
    var templates = new List<BIM_Template?>();

    for (int j = 0; j < 1000; j++) templates.Add(LoadTemplate()); 
    
    return templates;
}

public static BIM_Template LoadTemplate() 
{
    BIM_Template template = default;
    var template = TH_ExtractBimTemplate(ref template);

    return template;
}

所以,问题是如何防止这些内存泄漏并使用某些标准 C# 工具集从创建的模板中释放内存,或者如何让模板对象的 IntPtr 来使用库?

你不需要打电话给 TH_FreeMemory。您的结构内部没有任何指针。在 C++ 中,Mint 字段应为 std::array<uint32_t, MAX_MINUTIAE_SIZE> 或等效项。

你的template局部变量在栈上,它不使用任何堆内存,栈内存会在LoadTemplate()方法returns之前自动释放。

如果您想释放 TestDisposalIsCalledOnOutOfContext 中列表使用的内存,请执行以下操作:

templates = null;
// Collect all generations of memory
GC.Collect();