在C#中分配“非托管”内存

25

我正在使用C#编写一个程序,该程序使用了一个C++库,由于某些原因我需要分配一个非托管缓冲区并将其传递给该库。在C#中是否有方法可以实现这一点?

基本上我只需要在C#中执行类似于malloc的操作...

谢谢


2
@John Saunders: 我不确定这是否可靠,因为托管内存无法保证是连续的。您可能还需要钉住它,以防止垃圾回收器在使用它时将其移动。 - Joshua
6
@Joshua 嗯?托管内存非常有保证是连续的。虽然它不保证始终在同一位置,但当它确实在同一位置时,它是连续的,并且可以使用“fixed”来保持稳定。 - Roman Starkov
另外,如果您将缓冲区传递到函数中,并且C++程序在返回时已经完成了它,您可以使用pinvoke,传递一个byte[],让编译器为您处理其余部分。 - Warty
4个回答

46

试试这样做:

using System;
using System.Runtime.InteropServices;

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

这个代码使用了 Marshal.AllocHGlobal 方法:

使用指定的字节数从进程的非托管内存中分配内存。


27
请确保使用 FreeHGlobal() 方法释放它。同时,为了避免异常,您可能希望创建一个实现 IDisposable 接口的包装类来分配内存,这样您就可以在 using 语句中分配内存,在 Dispose 方法中释放内存。 - Ron Warholic

9
您也可以使用字节数组实现此功能。
通过使用不安全的例程和fixed语句来实现:
``` 您需要在unsafe上下文中声明方法,并使用fixed语句将堆上的数组固定到本地指针。 ```
static unsafe void PerformOperation()
{
    byte[] buf = new byte[1024];
    fixed (void* ptr = &buf[0])
    {
        SomeUnmanagedFunction(new IntPtr(ptr));
    }
}

问题在于,SomeUnmanagedFunction函数在返回后并且代码已经退出fixed块后不允许再操作该指针。这是一个重要的问题。因此,如果您执行以下操作:
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
}

你这样做只会自找麻烦。在这种情况下,你可能想使用GCHandle,它可以将托管对象固定在堆中。但这也可能会带来麻烦,因为你需要及时取消固定,否则就有可能造成堆碎片。

总的来说,我建议确保正确地P/Invoke到函数中,这样可能的话,marshaller就可以为你完成这项工作。相比GlobalAlloc,我更喜欢fixed,因为其范围更清晰。我无法确定我最不喜欢GlobalAlloc和GCHandle中的哪一个,因为它们都要求你做更多的工作,因为GC或语言不能替你完成这些工作。


3
这是我们需要使用特定字节数来分配和释放非托管内存的方法。
// Demonstrate how to call GlobalAlloc and 
// GlobalFree using the Marshal class.
IntPtr hglobal = Marshal.AllocHGlobal(100);
Marshal.FreeHGlobal(hglobal)

0
多年以后,在此期间: 在 .net6、7 中,微软为我们带来了类 "NativeMemory",其中包含 "AlignedAlloc" 等方法,这对于矢量化应用程序可能非常有用:MS writes 举例说明:
public static void* AlignedAlloc (UIntPtr byteCount, UIntPtr alignment);

这个方法是对C aligned_alloc API或者类似于Win32上的_aligned_malloc的平台相关的对齐分配API的一个薄包装。

当然,在这种情况下没有垃圾回收。为了避免内存泄漏,必须自己释放内存,使用"AlignedFree"。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接