2014-09-11 58 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其他答案描述。

相關問題