【问题标题】:allocating "unmanaged" memory in c#在 C# 中分配“非托管”内存
【发布时间】:2011-02-08 13:34:24
【问题描述】:

我正在用 C# 编写一个使用 C++ 库的程序,出于某种原因,我需要分配一个非托管缓冲区以将其传递给库。有没有办法在 c# 中做到这一点? 基本上我只需要在 C# 中做一个 malloc...

谢谢

【问题讨论】:

  • @John Saunders:我不知道这是否可靠,因为不能保证托管内存是连续的。您可能还想固定它以防止 GC 在使用时移动它。
  • @Joshua 嗯?托管内存在很大程度上保证是连续的。不能保证会一直呆在同一个地方,但是当它出现时,它是连续的,并且有fixed 可以保持稳定。
  • 另一方面,如果你将缓冲区传递给一个函数并且 C++ 程序在它返回时完成了它,你可以使用 pinvoke,传入一个 byte[] 并让编译器处理剩下的交给你。

标签: c# memory unmanaged


【解决方案1】:

试试这样的:

using System;
using System.Runtime.InteropServices;

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

这使用Marshal.AllocHGlobal 方法:

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

【讨论】:

  • 确保使用FreeHGlobal() 释放它。另外为了异常安全,您可能希望创建一个 IDisposable 包装类来分配内存,以便您可以在 using 语句中分配以释放 Dispose 上的内存。
【解决方案2】:

您也可以为此使用字节数组。

您可以通过使用不安全的例程和固定语句来做到这一点:

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

问题 - 这是一个重要的问题 - 是 SomeUnmanagedFunction 在它返回并且代码退出固定块之后不允许触摸该指针。所以如果你这样做:

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/Invoking 到函数中,以便可能的编组器可以为您完成这项工作。我喜欢 fix 比 GlobalAlloc 更好,因为它的范围很明确。我无法决定我最不喜欢 GlobalAlloc 和 GCHandle 中的哪一个。两者都要求你做更多的工作,因为 GC 或语言不会为你做这件事。

【讨论】:

    【解决方案3】:

    这就是我们需要使用特定字节数来分配和释放非托管内存的方式。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-14
      • 2013-12-14
      • 1970-01-01
      • 2010-12-03
      • 2011-09-21
      相关资源
      最近更新 更多