2009-12-11 11 views
22

ho la seguente struct:Marshal.AllocHGlobal VS Marshal.AllocCoTaskMem, Marshal.SizeOf VS sizeof()

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
public struct WAVEHDR 
{ 
    internal IntPtr lpData; // pointer to locked data buffer 
    internal uint dwBufferLength; // length of data buffer 
    internal uint dwBytesRecorded; // used for input only 
    internal IntPtr dwUser; // for client's use 
    internal uint dwFlags; // assorted flags (see defines) 
    internal uint dwLoops; // loop control counter 
    internal IntPtr lpNext; // reserved for driver 
    internal IntPtr reserved; // reserved for driver 
} 

devo allocare memoria non gestita per memorizzare un'istanza di sopra struct. Un puntatore a questa struttura verrà passato alle funzioni waveOut win32 api (waveOutPrepareHeader, waveOutWrite, waveOutUnprepareHeader).

  1. Devo usare Marshal.AllocHGlobal() o Marshal.AllocCoTaskMem()? Qual è la differenza?
  2. Devo passare sizeof(WAVEHDR) o Marshal.SizeOf(typeof(WAVEHDR)) al metodo di allocazione della memoria? Qual è la differenza?

NOTA che la memoria allocata deve essere bloccata.

risposta

38

Un programma Windows ha sempre almeno due heap in cui è allocata memoria non gestita. Il primo è l'heap del processo predefinito, utilizzato da Windows quando è necessario allocare memoria per conto del programma. Il secondo è un heap utilizzato dall'infrastruttura COM da allocare. Il marshaller .NET P/Invoke presuppone che questo heap sia stato utilizzato da qualsiasi codice non gestito la cui firma di funzione richiede la disallocazione della memoria.

AllocHGlobal alloca dall'heap del processo, AllocCoTaskMem alloca dall'heap COM.

Ogni volta che si scrive codice di interoperabilità non gestito, si dovrebbe sempre evitare una situazione in cui il codice che alloca la memoria non gestita non è lo stesso del codice che lo libera. Ci sarebbero buone probabilità che venga utilizzato il de-allocatore sbagliato. Questo è particolarmente vero per qualsiasi codice che si interponi con un programma C/C++. Tali programmi hanno il proprio allocatore che utilizza il proprio heap, creato dal CRT all'avvio. La ridistribuzione di tale memoria in altro codice è impossibile, non è possibile ottenere in modo affidabile l'handle dell'heap. Questa è una fonte molto comune di problemi P/Invoke, specialmente perché la funzione HeapFree() in XP e precedenti ignorano silenziosamente le richieste di liberare memoria che non è stata allocata nell'heap destro (con perdite di memoria allocata) ma Vista e Win7 si bloccano programma con un'eccezione.

Non c'è bisogno di preoccuparsi di questo nel vostro caso, le funzioni API mmsystem che si stanno usando sono pulite. Sono stati progettati per garantire lo stesso codice che assegna anche i deallocati. Questo è uno dei motivi per cui devi chiamare waveInPrepareHeader(), alloca i buffer con lo stesso codice che alla fine li rilascia. Probabilmente con l'heap del processo predefinito.

È necessario solo allocare la struttura WAVEHDR. E tu sei responsabile di rilasciarlo quando hai finito. Le API mmsystem non lo fanno per te, soprattutto perché non possono farlo in modo affidabile. Di conseguenza, è possibile utilizzare uno degli allocatori, è sufficiente assicurarsi di chiamare il metodo libero corrispondente. Tutte le API di Windows funzionano in questo modo. Io uso CoTaskMemAlloc() ma in realtà non è una preferenza. Solo che se sto chiamando codice mal progettato, è leggermente più probabile utilizzare l'heap COM.

Non si dovrebbe mai usare sizeof() in uno scenario di interoperabilità. Restituisce la dimensione gestita del tipo di valore. Potrebbe non essere lo stesso dopo che il marshaller P/Invoke ha tradotto un tipo di struttura in base alle direttive [StructLayout] e [MarshalAs]. Solo Marshal.SizeOf() offre un valore corretto garantito.


AGGIORNAMENTO: c'era un grande cambiamento in VS2012. La libreria di runtime C inclusa con esso ora alloca dall'heap del processo predefinito invece di utilizzare il proprio heap. A lungo termine, questo rende AllocHGlobal la strada più probabile per il successo.

+1

Esistono differenze di prestazioni tra le due funzioni di allocazione? – DxCK

+3

'AllocCoTaskMem' è più performante. 'AllocHGlobal' chiama' LocalAlloc', che ha la seguente nota: "Le funzioni locali hanno un sovraccarico maggiore e forniscono meno funzioni rispetto ad altre funzioni di gestione della memoria." Vedere https://msdn.microsoft.com/en-us/library/windows/desktop/aa366723(v=vs.85).aspx – IamIC

2
1

2) Per quanto ne so il sizeof può essere utilizzato solo con i tipi che hanno una dimensione predefinita al tempo di compilazione.

Quindi utilizzare Marshal.SizeOf(typeof(WAVEHDR)).

Problemi correlati