简体   繁体   English

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

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

Please, advise me on how to free memory from the created unsafe C# struct (s) using some standard C# toolset or how get I get the IntPtr of those objects to use the default provided custom C++ library?请告诉我如何使用一些标准 C# 工具集从创建的unsafe C# struct中释放内存,或者如何让这些对象的IntPtr使用默认提供的自定义 C++ 库?

The problem details (UPD):问题详细信息(UPD):

  1. I create the C# unsafe struct and pass it to C++ dll that I can't change TH_ExtractBimTemplate(ref createdStruct) .我创建了 C# unsafe struct并将其传递给我无法更改的 C++ dll TH_ExtractBimTemplate(ref createdStruct) The dll updates its content. dll 更新其内容。 And in addition to that, the dll saves the reference to the struct object inside of it in an internal list.除此之外,dll 将对其内部结构对象的引用保存在内部列表中。 Here is the struct definition:这是结构定义:

     public unsafe struct BIM_Template { public ushort ImageSizeX; public ushort ImageSizeY; public fixed uint Mint[MAX_MINUTIAE_SIZE]; public uint Reserve; }
  2. After the API call returns, I use the data in the struct populated by the C++ dll in my C# code. API 调用返回后,我在 C# 代码中使用由 C++ dll 填充的结构中的数据。

  3. I need to free the memory used by the struct and C++.我需要释放结构和 C++ 使用的内存。 The dll has an API to do this, TH_FreeMemory . dll 有一个 API 可以执行此操作, TH_FreeMemory

For step #3 I need to pass the object reference (I presume IntPtr ) to C++ library or I need to Free the memory it was occupying with some C# instrument.对于第 3 步,我需要将对象引用(我假设为IntPtr )传递给 C++ 库,或者我需要释放它被某些 C# 工具占用的内存。

The Garbage Collection doesn't work even if there are no reference in my C# code to the object, I assume, because of the struct object reference is stored in the list in the dll that I don't control.我假设,即使我的 C# 代码中没有对该对象的引用,垃圾收集也不起作用,因为结构对象引用存储在我无法控制的 dll 的列表中。 When TH_FreeMemory on the struct object is called, it removes it from the list and release the memory with delete , but I can't generate the C# IntPtr to pass it to the TH_FreeMemory for that...当调用结构对象上的TH_FreeMemory时,它会将其从列表中删除并使用delete释放内存,但我无法生成 C# IntPtr以将其传递给TH_FreeMemory ......

How can I do that - release the memory with just C# tools, ignoring the list dll or generate the IntPtr for this struct?我该怎么做 - 仅使用 C# 工具释放内存,忽略列表 dll 或为此结构生成IntPtr

The implementation details:实施细则:

This is how I create and initialize it:这就是我创建和初始化它的方式:

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

Where TH_ExtractBimTemplate(...) is the method that is pulled from the C++ dll in this way:其中TH_ExtractBimTemplate(...)是以这种方式从 C++ dll 中提取的方法:

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

The TemplateHelper.dll provides me a C++ method to release the memory - TH_FreeMemory : TemplateHelper.dll为我提供了一种释放内存的 C++ 方法 - TH_FreeMemory

int WINAPI TH_FreeMemory( void *memblock,  BIM_MemBlockType memblock_type )

This is how I plug it into C#这就是我将它插入 C# 的方式

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

Current solutions I tried:我尝试过的当前解决方案:

  • I need IntPtr of the created unsafe struct (the template variable) but I don't know how to get it, to free allocated memory with TH_FreeMemory dll method我需要创建的unsafe struct (模板变量)的IntPtr ,但我不知道如何获取它,以使用TH_FreeMemory dll 方法释放分配的内存
  • I have tried to create a bunch of these unsafe struct type templates in the method that create them and return void, leaving no references to the created templates, but the garbage collector doesn't free memory.我试图在创建它们并返回 void 的方法中创建一堆这些unsafe struct类型模板,不留下对创建模板的引用,但垃圾收集器不会释放内存。 I assume that is, because of the object type is unsafe struct .我假设是因为对象类型是unsafe struct At least, I've waited for 40 minutes and memory wasn't released.至少,我等了40分钟,内存没有释放。
  • I have tried the approach below to release the memory with Marshal.FreeHGlobal(IntPtr ptr) but that doesn't reduce the amount of unmanaged memory used by the app as well here is the code:我尝试了以下方法来使用Marshal.FreeHGlobal(IntPtr ptr)释放内存,但这并没有减少应用程序使用的非托管内存量,这里是代码:
[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;
}

So, the question is how can I prevent these memory leaks and free memory from the created templates using some standard C# toolset or how get I get the IntPtr of the template object to use the library?因此,问题是如何使用某些标准 C# 工具集从创建的模板中防止这些内存泄漏和释放内存,或者如何让模板对象的IntPtr使用该库?

You don't need to call TH_FreeMemory .您无需调用TH_FreeMemory Your structure doesn't have any pointers inside.您的结构内部没有任何指针。 In C++, the Mint field should be std::array<uint32_t, MAX_MINUTIAE_SIZE> or an equivalent.在 C++ 中, Mint字段应该是std::array<uint32_t, MAX_MINUTIAE_SIZE>或等效项。

Your template local variable is on the stack, it does not use any heap memory, and the stack memory will be freed automatically just before the LoadTemplate() method returns.您的template局部变量在堆栈上,它不使用任何堆内存,并且堆栈内存将在LoadTemplate()方法返回之前自动释放。

if you wanna free the memory used by the list in TestDisposalIsCalledOnOutOfContext , do this:如果您想释放TestDisposalIsCalledOnOutOfContext中列表使用的内存,请执行以下操作:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM