Unity NativeArray 内存解析

Unity NativeArray 内存解析

本文要揭示NativeArray真的是使用Native Memory的整个过程.

代码来源:C#部分 C++部分来自于IDA pro解析UnityPlayer.dll

C#代码

先来看C#部分中的

public unsafe struct NativeArray<T> : IDisposable, IEnumerable<T>, IEquatable<NativeArray<T>> where T : struct
{
        internal void*                    m_Buffer;
        internal int                      m_Length;

是一个模板类

先来看下构造函数


        public NativeArray(int length, Allocator allocator, NativeArrayOptions options = NativeArrayOptions.ClearMemory)
        {
            Allocate(length, allocator, out this);
            if ((options & NativeArrayOptions.ClearMemory) == NativeArrayOptions.ClearMemory)
                UnsafeUtility.MemClear(m_Buffer, (long)Length * UnsafeUtility.SizeOf<T>());
        }

        public NativeArray(T[] array, Allocator allocator)
        {
            if (array == null)
                throw new ArgumentNullException(nameof(array));

            Allocate(array.Length, allocator, out this);
            Copy(array, this);
        }

        public NativeArray(NativeArray<T> array, Allocator allocator)
        {
            AtomicSafetyHandle.CheckReadAndThrow(array.m_Safety);
            Allocate(array.Length, allocator, out this);
            Copy(array, 0, this, 0, array.Length);
        }

可以发现内存分配的函数就是Allocate

        static void Allocate(int length, Allocator allocator, out NativeArray<T> array)
        {
            long totalSize = UnsafeUtility.SizeOf<T>() * (long)length;
            CheckAllocateArguments(length, allocator, totalSize);

            array = default(NativeArray<T>);
            array.m_Buffer = UnsafeUtility.Malloc(totalSize, UnsafeUtility.AlignOf<T>(), allocator);
            array.m_Length = length;
            array.m_AllocatorLabel = allocator;

            array.m_MinIndex = 0;
            array.m_MaxIndex = length - 1;
            DisposeSentinel.Create(out array.m_Safety, out array.m_DisposeSentinel, 1, allocator);
            InitStaticSafetyId(ref array.m_Safety);
        }

分配了具体的内存大小,发现关键代码是UnsafeUtility.Malloc(totalSize, UnsafeUtility.AlignOf(), allocator);

unsafe public static extern void* Malloc(long size, int alignment, Allocator allocator);

这是外部调用函数,可以从IDA pro中获得

C++部分

void *__cdecl UnsafeUtility_CUSTOM_Malloc(unsigned int a1, int a2, int a3, int a4)
{
  int v4; // ecx
  void *v5; // esi
  struct IDSPGraph *v6; // eax
  int v7; // eax
  const char *v9; // [esp+4h] [ebp-40h]
  char *v10; // [esp+8h] [ebp-3Ch]
  char *v11; // [esp+Ch] [ebp-38h]
  char *v12; // [esp+10h] [ebp-34h]
  char *v13; // [esp+14h] [ebp-30h]
  __int128 v14; // [esp+18h] [ebp-2Ch]
  int v15; // [esp+28h] [ebp-1Ch]
  int v16; // [esp+2Ch] [ebp-18h]
  char v17; // [esp+30h] [ebp-14h]
  char v18; // [esp+34h] [ebp-10h]
  int v19; // [esp+3Ch] [ebp-8h]
  int v20; // [esp+40h] [ebp-4h]

  v4 = 16;
  v19 = 0;
  if ( a3 > 0 )
    v4 = a3;
  v20 = 0;
  v5 = 0;
  switch ( a4 )
  {
    case 2:
      v5 = ManagedTempMemScope::Allocate(a1, v4);
      break;
    case 3:
      v5 = malloc_internal(a1, v4, 2, 0, (int)&byte_111478C4, 71);
      break;
    case 4:
      v5 = malloc_internal(a1, v4, 105, 0, (int)&byte_111478C4, 82);
      break;
    case 5:
      v6 = GetIDSPGraph();
      if ( v6 )
      {
        v5 = (void *)(**(int (__stdcall ***)(unsigned int))v6)(a1);
        if ( !v5 )
        {
          v7 = Scripting::CreateInvalidOperationException(&v18, "Invalid context for allocating audio kernel memory");
          ScriptingExceptionPtr::operator=(&v19, v7);
        }
      }
      else
      {
        v10 = &byte_111478C4;
        v11 = &byte_111478C4;
        v12 = &byte_111478C4;
        v17 = 1;
        v9 = "DSPGraph module is not loaded";
        v13 = &byte_111478C4;
        v14 = _xmm;
        v15 = 0;
        v16 = 0;
        DebugStringToFile((const struct DebugStringToFileData *)&v9);
      }
      break;
    default:
      break;
  }
  if ( v19 || v20 )
    scripting_raise_exception(v19, v20);
  return v5;
}

主要是用switch(Allocator)来选择内存类型,Allocator类型如下

    public enum Allocator
    {
        Invalid = 0,
        None = 1,
        Temp = 2,
        TempJob = 3,
        Persistent = 4,
        AudioKernel = 5,
    }

与上面的分配内存方式对应起来了.

ManagedTempMemScope::Allocate

malloc_internal

这些都是Unity Native Momery内核分配函数,具体可以去看浅谈Unity内存管理里面有个初步认识.

总结

为什么Unity要使用NativeArray而不是List,应该有以下几点好处

  • 不需要GC,速度快,生成和销毁代价低,适合作为ECS中的临时数据结构.
  • Native可以直接调用,没有中间商赚差价.

坏处么

  • 功能少,增加学习成本吧
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值