2014-09-11 61 views
3

我需要做这样的事情:使用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); 
} 

或将分配memeory被自动清理一次函数退出? 我想(从我读过的)这是后者,但我不确定!

任何澄清赞赏!

回答

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

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

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

要完成,仅当结构包含BSTR,SAFEARRAY或COM接口指针时才需要清除。具有显式释放调用且需要结构声明中的[MarshalAs]属性的资源。当你使用pinvoke的时候,这是非常罕见的。当您使用COM interop时,并不罕见,同样在底层使用StructureToPtr(),但CLR会自动进行调用。

1

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

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

2

没有,如果你使用AllocHGlobal必须释放它自己分配内存。否则内存将被泄露。

下面是相关的部分从documentation

的指针新分配的内存。该内存必须使用Marshal.FreeHGlobal方法发布

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其他答案描述。

相关问题