2010-04-15 27 views
19

Estoy escribiendo un programa en C# que usa una biblioteca C++, y por alguna razón necesito asignar un búfer no administrado para pasarlo a la lib. ¿Hay alguna manera de hacer esto en C#? Básicamente yo sólo necesita hacer un malloc en C# ...asignando memoria "no administrada" en C#

Gracias

+0

¿Qué pasa con 'new byte [1024]'? –

+2

@ John Saunders: No sé si eso sería confiable ya que no se garantiza que la memoria administrada sea contigua. También es probable que desee fijarlo para evitar que el GC lo mueva mientras lo estaba utilizando. – Joshua

+4

@Joshua Huh? La memoria administrada está garantizada que es contigua. No está garantizado que permanezca en el mismo lugar, pero cuando lo hace, es contiguo, y hay 'fijo 'para mantenerlo estable. –

Respuesta

35

intentar algo como esto:

using System; 
using System.Runtime.InteropServices; 

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

Este método utiliza la Marshal.AllocHGlobal:

Asigna memoria desde la memoria no administrada del proceso utilizando la cantidad de bytes especificada.

+19

Asegúrate de liberarlo con 'FreeHGlobal()'. Además, para que sea una excepción segura, probablemente desee crear una clase contenedora 'IDisposable' para asignar la memoria, de modo que pueda asignar una instrucción' using' para liberar la memoria en 'Dispose'. –

7

También puede usar una matriz de bytes para esto.

Esto se hace mediante el uso de una rutina insegura y el estado fijo:

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

La cuestión - y esto es una muy importante - es que SomeUnmanagedFunction no se le permite tocar ese puntero después de que haya regresado y el código ha salido del bloque fijo. Entonces, si usted hace algo como esto:

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 
} 

usted está pidiendo nada más que problemas. En este caso, probablemente desee utilizar un GCHandle, que puede fijar un objeto administrado en el montón. Esto también puede ser problemático, ya que NECESITA destrabarlo de manera oportuna o corre el riesgo de fragmentar su pila.

En general, recomendaría asegurarse de que está P/Invocando correctamente en la función para que el tal Marshall pueda hacer este trabajo por usted. Me gusta mejor que Fix GlobalAlloc porque su alcance es claro. No puedo decidir cuál me gusta menos de GlobalAlloc y GCHandle. Ambos requieren para realizar más trabajo ya que el GC o el idioma no lo harán por usted.

2

Así es como tenemos que asignar y liberar memoria no administrada mediante el uso de un número específico de bytes.

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