2010-04-15 6 views
19

Sto scrivendo un programma in C# che utilizza una libreria C++ e per qualche motivo ho bisogno di allocare un buffer non gestito per passarlo alla lib. C'è un modo per farlo in C#? Fondamentalmente vorrei solo bisogno di fare un malloc in C# ...allocare memoria "non gestita" in C#

Grazie

+0

E il 'nuovo byte [1024]'? –

+2

@John Saunders: Non so se sarebbe affidabile dato che la memoria gestita non è garantita come contigua. Probabilmente vorrai appenderlo anche per evitare che il GC lo sposti mentre era in uso. – Joshua

+4

@Joshua Huh? La memoria gestita è garantita per essere contigua. Non è garantito rimanere nello stesso posto, ma quando lo fa, è contiguo, e c'è "riparato" per mantenerlo stabile. –

risposta

35

provare qualcosa di simile:

using System; 
using System.Runtime.InteropServices; 

class Example 
{ 
    static void Main() 
    { 
     IntPtr pointer = Marshal.AllocHGlobal(1024); 
    } 
} 

Questo utilizza il metodo Marshal.AllocHGlobal:

Alloca memoria dalla memoria non gestita del processo utilizzando il numero specificato di byte.

+19

Assicurati di liberarlo con 'FreeHGlobal()'. Anche per essere sicuri delle eccezioni, probabilmente si desidera creare una classe wrapper 'IDisposable' per allocare la memoria in modo da poter allocare in una istruzione' using' per liberare la memoria su 'Dispose'. –

7

Per questo è anche possibile utilizzare un array di byte.

A tale scopo, impiegando la procedura non sicura e la dichiarazione fissa:

static unsafe void PerformOperation() 
{ 
    byte[] buf = new byte[1024]; 
    fixed (void* ptr = &buf[0]) 
    { 
     SomeUnmanagedFunction(new IntPtr(ptr)); 
    } 
} 

Il problema - e questo è molto importante - è che SomeUnmanagedFunction non è permesso di toccare quel puntatore dopo che è tornato e il codice è uscito dal blocco fisso. Quindi, se fai qualcosa di simile:

static void PerformFabulousTrick() 
{ 
    byte[] buf = new byte[1024]; 
    fixed (void *ptr = &buf[0]) 
    { 
     SetBuffer(ptr, buf.Length); 
    } 
    FillBuffer(); // puts data in buf - NOT - may crash hard 
} 

non stai chiedendo altro che guai. In questo caso, probabilmente si desidera utilizzare uno GCHandle, che può bloccare un oggetto gestito nell'heap. Questo può anche essere fastidioso nel fatto che è necessario sbloccarlo tempestivamente o rischiare di frammentare il tuo heap.

In generale, ti consiglio di assicurarti di inserire P/Invocare correttamente la funzione in modo che il marshaller possa farlo per te. Mi piace riparato meglio di GlobalAlloc poiché il suo scopo è chiaro. Non riesco a decidere quale mi piace meno di GlobalAlloc e GCHandle. Entrambi richiedono di fare più lavoro poiché il GC o la lingua non lo faranno per te.

2

Ecco come è necessario assegnare e liberare memoria non gestita utilizzando un numero specifico di byte.

// Demonstrate how to call GlobalAlloc and 
// GlobalFree using the Marshal class. 
IntPtr hglobal = Marshal.AllocHGlobal(100); 
Marshal.FreeHGlobal(hglobal)