提取UnityProfiler内存数据

功能

  • 提取Unity Profiler窗口的内存Detailed数据
  • 支持Editor和通过IP连接手机来监测数据
  • 可以提取指定大小范围内的数据, 例如只输出内存大于1MB的数据
  • 可以指定输出的层级( 深度 ), 例如只输出2级数据
  • 输出的数据按照其占内存大小来排序

如何使用

  1. 打开窗口Window/Extract Profiler Memory

提取UnityProfiler内存数据_第1张图片
2. 选择连接的设备, Editor或手机

提取UnityProfiler内存数据_第2张图片
3. 将Profiler窗口切换到Memory视图, 并选择Detailed选项(方便数据显示)

提取UnityProfiler内存数据_第3张图片
4. 点击Take Sample, 获取内存快照
5. 选择合适的内存大小过滤和深度过滤
6. 点击Extract Memory,将数据输出到txt文件

效果截图

  1. Android环境

提取UnityProfiler内存数据_第4张图片
2. Editor环境

提取UnityProfiler内存数据_第5张图片

使用环境

Unity 5.6及以上

实现方法介绍

数据来自哪里

利用ReSharper插件的反编译功能, 可以得到UnityEditor.ProfilerWindow的CS部分的代码, 如下图

提取UnityProfiler内存数据_第6张图片

我们要提取的数据就是红框标记字段, 字段的说明如下

  • UnityEditor.ProfilerWindow: 对应Editor下的Profiler窗口
  • ProfilerWindow.m_ProfilerWindows:Profiler窗口下各种类型窗口的集合
  • ProfilerWindow.m_CurrentArea: 当前窗口的类型, 我们要提取的数据来自ProfilerArea.Memory
  • ProfilerWindow.m_MemoryListView: 内存窗口下的内存数据记录类
  • MemoryTreeList.m_Root: 记录了内存对象列表的根节点, 即所有内存对象占的总内存
  • MemoryElement.children: 当前内存对象类型包含的子内存对象
  • MemoryElement.totalMemory: 当前内存对象所占的总内存
  • MemoryElement.name: 当前内存对象的名字, 例如: Other, Assets, ShaderLab

通过反射提取数据

什么是反射

在.NET中的反射可以实现从对象的外部来了解对象(或程序集)内部结构的功能

作用:

  • 可以动态创建出对象并执行它其中的方法。
  • 可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。
  • 有了反射,可对每一个类型了如指掌。
  • 还可以直接创建对象,即使这个对象的类型在编译时还不知道。

此工具利用反射原理, 通过递归遍历MemoryElement.children来提取我们所需的数据结构totalMemory,name, totalMemory存入自定义类MemoryElement, 同时增加字段_depth来记录该内存对象的深度, 方便数据过滤

关键代码如下

    public static MemoryElement Create(Dynamic srcMemoryElement, int depth, int filterDepth, float filterSize)
    {
        if (srcMemoryElement == null) return null;
        var dstMemoryElement = new MemoryElement { _depth = depth };
        Dynamic.CopyFrom(dstMemoryElement, srcMemoryElement.InnerObject,
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetField);

        var srcChildren = srcMemoryElement.PublicInstanceField("children");
        if (srcChildren == null) return dstMemoryElement;
        foreach (var srcChild in srcChildren)
        {
            var memoryElement = Create(new Dynamic(srcChild), depth + 1, filterDepth, filterSize);
            if (memoryElement == null) continue;
            if (depth > filterDepth) continue;
            if (!(memoryElement.totalMemory >= filterSize)) continue;
            dstMemoryElement.children.Add(memoryElement);
        }

        dstMemoryElement.children.Sort();
        return dstMemoryElement;
    }

项目地址

  • jingangxin36/ExtractProfilerMemory

参考

  • Unity Editor 提取Profiler数据 - Memory

你可能感兴趣的:(Unity,3D,Unity性能优化)