使用PInvoke中的结构后,是否需要释放内存
本文关键字:是否 释放 内存 PInvoke 结构 使用 | 更新日期: 2023-09-27 18:21:41
我需要做这样的事情吗:
TEXTMETRIC tm;
bool isTrueType = false;
if (NativeMethods.GetTextMetrics(hDC, out tm))
{
isTrueType = ((PitchAndFamily)tm.tmPitchAndFamily & PitchAndFamily.TMPF_TRUETYPE) == PitchAndFamily.TMPF_TRUETYPE;
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf<TEXTMETRIC>(tm));
Marshal.StructureToPtr<TEXTMETRIC>(tm, ptr, true);
Marshal.FreeHGlobal(ptr);
}
或者一旦函数退出,分配的内存会自动清理吗?我认为(从我读到的)是后者,但我不确定!
感谢任何澄清!
Marshal.StructureToPtr<TEXTMETRIC>(tm, ptr, true);
在这里使用true是非常错误的。使用AllocHGlobal()分配的内存未初始化,并且包含随机字节。它不包含需要在被方法覆盖之前发布的结构的早期版本。
从技术上讲,这可能会导致非常难以诊断的随机崩溃,具体取决于随机字节值。因为TEXTMETRIC不包含任何需要清理的成员,所以您侥幸逃脱了惩罚。FreeHGlobal()调用就足够了,不需要Marshal.DestroyStructure(),你应该把它放在finally块中,这样它就可以安全异常了。这回答了你的问题。
为了完成清理,只有当结构包含BSTR、SAFEARRAY或COM接口指针时才需要进行清理。具有显式发布调用并且在结构声明中需要[MarshalAs]属性的资源。当你使用pinvoke时,这种情况非常罕见。当您使用COM互操作时,也会在后台使用StructureToPtr(),这并不罕见,但CLR会自动进行调用。
您调用的函数GetTextMetrics
希望调用方为结构分配和取消分配内存。如果使用AllocHGlobal
进行分配,则必须使用FreeHGlobal
解除分配。
然而,所有这些都是不必要的。当您声明tm
时,您正在分配结构。没有什么需要了。通过从不调用AllocHGlobal
来避免调用FreeHGlobal
。
TEXTMETRIC tm;
bool isTrueType = false;
if (NativeMethods.GetTextMetrics(hDC, out tm))
{
isTrueType = ((PitchAndFamily)tm.tmPitchAndFamily & PitchAndFamily.TMPF_TRUETYPE) == PitchAndFamily.TMPF_TRUETYPE;
}
避免手动分配也可以避免对StructureToPtr
进行其他答案所描述的中断呼叫,或者任何呼叫。
否,如果使用AllocHGlobal
分配内存,则必须自己释放内存。否则,内存将被泄露。
这是文件中的相关部分
指向新分配的内存的指针。必须释放此内存使用Marshal.FreeHGlobal方法。
如果手动分配非托管内存(并且您正在这样做),则需要手动释放它。添加finally
块以确保没有异常会干扰释放内存。
不过,您的示例没有多大意义,因为您将tm
复制到了一个从未使用过的内存块中。