栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 游戏开发 > 其他

Unity NativeArray 内存解析

其他 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Unity NativeArray 内存解析

Unity NativeArray 内存解析

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

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

C#代码

先来看C#部分中的

public unsafe struct NativeArray : IDisposable, IEnumerable, IEquatable> 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());
        }

        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 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 array)
        {
            long totalSize = UnsafeUtility.SizeOf() * (long)length;
            CheckAllocateArguments(length, allocator, totalSize);

            array = default(NativeArray);
            array.m_Buffer = UnsafeUtility.Malloc(totalSize, UnsafeUtility.AlignOf(), 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可以直接调用,没有中间商赚差价.

坏处么

  • 功能少,增加学习成本吧
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/905740.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号