C#-将任何不安全的非托管类型转换为托管类型,而无需任何新的内存分配-保持相同的内存大小

时间:2019-01-20 08:37:34

标签: memory-leaks .net-core marshalling managed

我想将ushort数组转换为short数组,而无需在C#内核中分配任何新内存。

还可以将任何类型转换,例如byte []转换为short [],反之亦然-转换需要在内存中为源和目标保持相同的大小

在C语言中有“联合”语法,可以通过多次类型转换来引用该类型-我没有发现C#的任何等效方法(仅适用于非原始类型)。

一种方法是像这样编码

ushort[] res = new ushort[1024 * 1024 * 1024];
short[] s = new short[1024 * 1024 * 1024];
Buffer.BlockCopy(s, 0, res, 0, s.Length * 2);

...但是,我不会分配's'值-它消耗太多内存,并可能导致内存泄漏。

我使用的另一种替代方法是使用不安全模式。

代码:

unsafe
{
    ushort[] res = new ushort[1024*1024*1024]; // large allocating
    fixed (ushort* ss = &res[0])
    {
        IntPtr ps = (IntPtr)ss;
        short[] s0 = (short[])Marshal.PtrToStructure(ps, typeof(short[]));
    }
}

遇到异常。

  

没有为此对象定义无参数的构造函数。

     

...

     

在System.RuntimeTypeHandle.CreateInstance(运行时类型,布尔publicOnly,布尔wrapExceptions,布尔&canBeCached,RuntimeMethodHandleInternal和ctor)

     

在System.RuntimeType.CreateInstanceSlow(布尔publicOnly,布尔wrapException,布尔skipCheckThis,布尔fillCache)

     

在System.Runtime.InteropServices.Marshal.PtrToStructure(IntPtr ptr,类型structureType)

我最终如何在不需要分配新内存的情况下转换1G字节的大型数组?

我可以将数组类型从非托管类型转换为托管类型吗?

如果可能的话,我更喜欢使用不安全模式。


经过深入搜索,我找到了一个解决方案,我可以参与(并编辑这篇文章),但是存在如下问题:

如果数组的大小相同,则代码运行得很好-有一个新问题-如何针对非相同的数组基本类型大小(即short [] vs byte [])解决它?

我唯一不能将short []转换为byte []。

(感谢互联网上的一些博客: https://social.msdn.microsoft.com/Forums/vstudio/en-US/06ac44b0-30d8-44a1-86a4-1716dc431c62/how-to-convert-an-intptr-to-an-object-in-c?forum=clr

在C#核心和C#.NET上都可以使用

首先,创建一个类:

public static class MyConverter
{
    public static unsafe T GetInstance<T>(IntPtr pointer)
    {
        try
        {
            var fakeInstance = default(T);
            TypedReference typedReference = __makeref(fakeInstance);
            *(IntPtr*)(&typedReference) = pointer;
            T instance = (T) __refvalue(typedReference,T);
            return instance;
        }
        catch
        {
            return default(T);
        }
    }
}

并可以在这样的代码中使用它:

      ushort[] x = new ushort[1024];
      GCHandle handle1 = GCHandle.Alloc(x);
      IntPtr px = (IntPtr)handle1;
      x[0] = 1;
      x[1] = 2;
      x[2] = 3;
      short[] s = MyConverter.GetInstance<short[]>(px);

该解决方案将ushort []转换为short [],而不会浪费内存。

谢谢。

1 个答案:

答案 0 :(得分:-1)

您可以轻松地像这样进行转换:(ushort[])(object)myShortArray。 CLR允许这样做。

仅允许大小相同的基本数组元素类型。

在其他情况下,您可以使用Span将内存视为其他类型。

Span<int> asInts = MemoryMarshal.Cast<byte, int>(asBytes);