使用PInvoke中的结构后,是否需要释放内存?

时间:2014-09-11 12:48:11

标签: c# pinvoke

我需要做这样的事情:

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);
}

或者一旦函数退出,是否会自动清除分配的记忆? 我想(从我读过的)是后者,但我不确定!

任何解释都表示赞赏!

4 个答案:

答案 0 :(得分:5)

Marshal.StructureToPtr<TEXTMETRIC>(tm, ptr, true);

在这里使用 true 是非常错误的。您使用AllocHGlobal()分配的内存已初始化并包含随机字节。它 not 包含在被方法覆盖之前需要释放的结构的先前版本。

这可能在技术上导致非常难以诊断随机崩溃,具体取决于随机字节值。你侥幸成功,因为TEXTMETRIC不包含任何需要清理的成员。 FreeHGlobal()调用就足够了,不需要Marshal.DestroyStructure(),你应该将它放在finally块中,这样它就是异常安全的。哪个回答你的问题。

要完成,只有在结构包含BSTR,SAFEARRAY或COM接口指针时才需要清理。具有显式释放调用且在结构声明中需要[MarshalAs]属性的资源。当你使用pinvoke时,这种情况非常罕见。使用COM互操作时并不罕见,也使用了引擎盖下的StructureToPtr(),但CLR会自动进行调用。

答案 1 :(得分:4)

您调用的函数GetTextMetrics期望调用者为结构分配和释放内存。如果您使用AllocHGlobal进行分配,则必须使用FreeHGlobal取消分配。

然而,这一切都是不必要的。您在声明tm时分配结构。没有什么比这更需要了。从不致电FreeHGlobal,无需致电AllocHGlobal

TEXTMETRIC tm;
bool isTrueType = false;
if (NativeMethods.GetTextMetrics(hDC, out tm))
{
    isTrueType = ((PitchAndFamily)tm.tmPitchAndFamily & PitchAndFamily.TMPF_TRUETYPE) == PitchAndFamily.TMPF_TRUETYPE;
}

避免手动分配还可以避免对其他答案所描述的StructureToPtr进行断断续续的呼叫或任何呼叫。

答案 2 :(得分:2)

不,如果您使用AllocHGlobal分配内存,必须自行释放内存。否则记忆将被泄露。

以下是documentation

的相关部分
  

指向新分配的内存的指针。此内存必须才能释放   使用Marshal.FreeHGlobal方法。

答案 3 :(得分:1)

如果您手动分配非托管内存(并且您正在这样做),则需要手动释放它。添加finally块以确保没有异常会干扰释放内存。

但是,您的示例没有多大意义,因为您将tm复制到您从未使用过的内存块。