【问题标题】:How can I in C# stream.Read into unmanaged memory stream?我如何在 C# 流中。读入非托管内存流?
【发布时间】:2010-11-24 22:31:33
【问题描述】:

我可以在 C# 中使用 UnmanagedMemoryStream 读取非托管内存,但我该如何反其道而行之?

我想从托管流中直接读取到非托管内存中,而不是先读取到 byte[] 然后再复制。我正在对大量请求进行异步流读取,因此增加的内存很重要(更不用说额外的副本了)。

【问题讨论】:

  • 内存已在 C++ 中分配,但如果真的不可能,我可能不得不更改现有代码以接受指向固定托管内存的指针:(

标签: c# performance memory stream unmanaged


【解决方案1】:

如果您有一个已知的目标缓冲区并且您知道您的数据有多大,这实际上并不太难。再次强调,关键的实现是 UnmanagedMemoryStream 只是对原生字节序列的一个薄包装。

您要做的是以通常的方式获取指向您的本机目标缓冲区的指针。然后你可以在它上面构造一个 writable UnmanagedMemoryStream。将源流复制到目标流,瞧!一个副本已将您从托管内存世界转移到本机内存世界。在 C++/CLI 中,它看起来像这样:

void CopyStreamToNativePtr(Stream^ src, unsigned char* dst)
{
    // Assuming we want to start the copy at the beginning of src
    src->Seek(0, SeekOrigin::Begin);

    // Create an UnmanagedMemoryStream on top of the destination
    // with an appropriate size and capacity (We assume the buffer is
    // is sized to the source data in this function!)
    UnmanagedMemoryStream target(dst, src->Length, src->Length, FileAccess::Write);

    // Copy to your heart's content!
    src->CopyTo(%target);

    // We made the UnmanagedMemoryStream local so that we wouldn't have
    // to explicitly Dispose() of it.
}

【讨论】:

  • 如何从一个流中只复制一定数量的字节到另一个流? src->CopyTo 将复制整个流。我只想复制 n 个字节。
【解决方案2】:

我认为这是不可能的。当您谈论托管流时,我想您指的是 System.IO.Stream 的实例或其子类。

这个类的成员以byte[]为参数,是一个托管类。

我猜你最接近的方法是创建一个托管字节[],然后在一个不安全的块中创建一个字节*,然后将字节*传递给任何需要非托管引用的对象:

unsafe function test()
{
    var buffer = new byte[1024];
    fixed (byte* bufferPtr = &buffer[0])
    {   
        // Read bytes and pass the ptr to a function that needs to
        // operate on data directly 
    }
}

但这并不是你想要的

edit:不过要小心。你提到了一些关于异步读取的事情。一旦您超出固定边界,GC 可能会在内存中移动数组。而且,如果您将指针传递给某个继续在不同线程中运行的“不安全”函数,则该指针将指向无效的内存位置。

【讨论】:

    【解决方案3】:

    托管流始终需要对有效byte[] 对象的“托管”对象引用。但是,您可以使用托管 byte[] 代替非托管内存分配,因此也可以将其作为非托管内存块访问:

    byte[] data = new byte[];
    GCHandle pin = GCHandle.Alloc(data, GCHandleType.Pinned);
    try {
      IntPtr dataUnmanagedPtr = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0);
      // managed.Read(data, index, count);
      // use the unmanaged pointer here for unmanaged code
    } finally {
      pin.Free(); // but make sure that no unmanaged code uses the pinned data anymore upon release
    }
    

    【讨论】:

    • 我发现这是最好的解决方案有两个原因:1. 它不需要不安全的代码 2. 它可以防止 GC 在内存中移动我们的数组(只要我们需要)
    【解决方案4】:

    您可以使用 C# 并通过 Windows API 将文件直接读取到非托管内存中。

    如果您想从 FileStream 中读取数据,这可能会有所帮助。检查FileStream implementation 并做类似的事情。

    var handle = Win32Native.SafeCreateFile(path, fAccess, share, secAttrs, mode, flagsAndAttributes, IntPtr.Zero);
    
    fixed(byte* p = bytes) 
    {   
       r = Win32Native.ReadFile(handle, p + offset, count, out numBytesRead, IntPtr.Zero);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      • 2012-05-25
      • 2013-12-14
      • 2011-02-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多