如何获取 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):
我创建了 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;
}
在 API 调用 return 之后,我在我的 C# 代码中使用由 C++ dll 填充的结构中的数据。
我需要释放结构和 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
);
我目前尝试的解决方案:
- 我需要创建的
unsafe struct
(模板变量)的 IntPtr
,但我不知道如何获取它,以使用 TH_FreeMemory
dll 方法释放分配的内存
- 我试图在创建它们的方法中创建一堆这些
unsafe struct
类型模板并且 return void,没有留下对创建模板的引用,但垃圾收集器没有免费内存。我假设是,因为对象类型是 unsafe struct
。至少,等了40分钟,内存还没释放。
- 我尝试了下面的方法来使用
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;
}
所以,问题是如何防止这些内存泄漏并使用某些标准 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();
请告诉我如何使用一些标准 C# 工具集从创建的 unsafe
C# struct
(s) 中释放内存,或者如何获取这些对象的 IntPtr
使用默认提供的自定义 C++ 库?
问题详情(UPD):
我创建了 C#
unsafe struct
并将其传递给我无法更改的 C++ dllTH_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; }
在 API 调用 return 之后,我在我的 C# 代码中使用由 C++ dll 填充的结构中的数据。
我需要释放结构和 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
);
我目前尝试的解决方案:
- 我需要创建的
unsafe struct
(模板变量)的IntPtr
,但我不知道如何获取它,以使用TH_FreeMemory
dll 方法释放分配的内存 - 我试图在创建它们的方法中创建一堆这些
unsafe struct
类型模板并且 return void,没有留下对创建模板的引用,但垃圾收集器没有免费内存。我假设是,因为对象类型是unsafe struct
。至少,等了40分钟,内存还没释放。 - 我尝试了下面的方法来使用
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;
}
所以,问题是如何防止这些内存泄漏并使用某些标准 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();