2009-03-26 15 views
9

Ho un oggetto COM ipotetico con la seguente firmaIl C# ripulisce la memoria allocata C++?

void MemAlloc(ref double[] test, int membercount) 

cui la memoria è allocata in C++ utilizzando nuovo/malloc. Una volta che questo è in C#, usando RCW, come posso assicurarmi che la memoria sia liberata correttamente? Penserei sarebbe difficile per .NET liberare, considerando in C++ è necessario sapere se è stato allocato con new/malloc/mm_malloc prima di poterlo liberare correttamente. Quindi, qual è il modo appropriato per ripulire il mio array assegnato C++? Grazie.

risposta

8

Credo che dovresti usare CoTaskMemAlloc() per la memoria che vuoi liberare esplicitamente dal lato gestito. Il CLR si occuperà di liberare la memoria una volta che non è più raggiungibile. Se si desidera liberarlo in modo esplicito, è possibile utilizzare la routine Marshal.CoTaskFree() gestita.

In generale, il marshaler di interoperabilità e il CLR si attengono alle convenzioni della COM per liberare memoria; il destinatario è responsabile della liberazione della memoria. Pertanto, il marshalling CLR/Interop di solito si occupa della liberazione della memoria allocata in una chiamata nativa se tale memoria viene restituita al chiamante gestito.

Da Memory Management with the Interop Marshaler (MSDN):

Il gestore di marshalling di interoperabilità tenta sempre per liberare la memoria allocata da codice non gestito . Questo comportamento è conforme alle regole di gestione della memoria COM , ma differisce da dalle regole che governano il C++ nativo.

La confusione può sorgere se si prevede nativo comportamento C++ (nessuna memoria liberazione) quando si utilizza invoke piattaforma, che libera automaticamente la memoria per puntatori. Ad esempio, chiamando lo seguendo il metodo non gestito da una DLL C++ non viene automaticamente liberata alcuna memoria .

Il runtime utilizza sempre il metodo CoTaskMemFree per liberare memoria. Se la memoria con cui si sta lavorando è non allocata con il metodo CoTaskMemAlloc , è necessario utilizzare un IntPtr e liberare manualmente la memoria utilizzando il metodo appropriato .

+0

grazie, era esattamente quello che stavo cercando – Steve

6

Avvolgere in un oggetto che implementa IDisposable e assicurarsi che il wrapper C# venga eliminato.

Here's a blog I wrote su un modo semplice per implementare IDisposable.

+0

L'utilizzo di IDisposable è una buona strategia di gestione delle risorse, ma come si implementa il metodo Dispose per liberare effettivamente la memoria? –

1

Sono quasi sicuro al 100% che il CLR non libererà automaticamente la memoria allocata per il test (se fosse PInvoke sarei sicuro al 100%). Il motivo è, come fa il CLR a sapere cosa hai usato per allocare la memoria in primo luogo? Vale a dire che non è così.

Un modo più sicuro di scrivere questa funzione è la seguente

void MemAlloc(ref IntPtr arrayPtr, int membercount) 

Una volta che la chiamata è possibile effettuare le seguenti operazioni.

var count = GetTheCount(); 
var arrayPtr = IntPtr.Zero; 
obj.MemAlloc(ref arrayPtr, count); 
byte[] test = MarshalThePtrToByteArray(arrayPtr, count); 
Marshal.FreeCoTaskMem(arrayPtr); 

Ecco un'implementazione veloce e sporco di MarashalThePtrToByteArray

byte[] MarashalThePtrToByteArray(IntPtr ptr, int count) { 
    byte[] arr = new byte[count]; 
    for (int i = 0; i < count; i++) { 
    arr[i] = (byte)Marshal.PtrToStructure(ptr, typeof(byte)); 
    ptr = new IntPtr(IntPtr.ToInt64() + Marshal.SizeOf(typeof(byte))); 
    } 
    return arr; 
} 
+0

Per COM Interop il marshalling CLR/Interop utilizza la convenzione COM per rilasciare la memoria restituita al chiamante fintanto che la memoria è stata allocata con CoTaskMemAlloc(). –

+0

@Arnshea, ma in che modo il CLR sa che è stato allocato con CoTaskMemAlloc? Non può e molte implementazioni COM non utilizzano CoTaskMemAlloc per i dati. – JaredPar

+0

Vero. In questi casi, dove sta implementando il metodo nativo, dovrebbe usare CoTaskMemAlloc() invece di new/mallow(). Quindi il marshaler interop provvederà a liberare la memoria. –

Problemi correlati