Unity内存与资源管理

2023-11-09

内存管理是程序开发的核心问题,而资源的使用又与内存息息相关,因此本章想要梳理整个开发流程中Unity对于内存与资源的管理方式。

一、内存基础

1.1 基础概念

内存是暂时存放CPU中的运算数据,与硬盘等外部存储器交换的数据。在操作系统中,内存分为物理内存与虚拟内存。

CPU读取数据

CPU进行数据处理时,从内存或缓存中取出指令,放入指令寄存器,并对指令译码进行分解,进而对数据进行处理。从内存中读取数据很慢,通常CPU会将之前读取的数据缓存在多级Cache中,提升数据访问效率。因此,CPU会先从Cache中查找数据,若没有找到(Cache Miss),才会访问内存。

物理内存:物理内存可以理解为运行时内存,其对应于实际的存储硬件。

虚拟内存:管理不同进程使用的进程内部内存地址和物理内存地址的映射体系。

页:内存管理、映射中的基本单位。

内存交换(页面交换):当系统内存不足时,操作系统会创建交换文件(Swap file)或者分页文件(Paging file)记录暂时不用的物理内存页面中的数据,并将这部分数据交换到硬盘上,节省更多的物理内存。

1.2 移动设备与PC差异

  • 没有独立显卡,显存与CPU数据会存储在同一区域。
  • CPU的Cache与内存更小。因此移动端会严格限制资源大小。
  • 没有内存交换(IO速度慢、可擦写次数少)
  • IOS可以进行内存压缩:将不活跃的内存压缩到特定空间。

1.3 Android内存分布

上图可以看出运行时内存包括:方法区、堆栈以及线程内存。

Android中对内存有4种统计方式:VSS(虚拟内存)、RSS(实际物理内存:APP+所有共享内存)、PSS(APP+平均共享库内存)、USS(APP内存)。通常使用PSS来统计。

Android对进程的管理策略称为LMK(Low Memory Killer),kill优先级如下:

1.4 IOS内存分布

IOS内存分布

Clear Memory包括系统框架数据、可执行的二进制数据以及内存映射文件。Clear Memory以外的内存都是Dirty Memory。

当系统存在内存压力时,会先卸载一部分Clear Memory,当再次需要时会对其重新创建。但系统无法对Dirty Memory进行卸载,直到到达App的限制才会被终止回收。内存不足时,IOS会对Dirty Memory做压缩处理。

IOS中Resident Memory指的是App分配的物理内存。当App向系统申请内存时,虚拟内存是直接增长的。但如果申请完的内存并没有向里面写入数据,它并不会产生实际的物理内存分配。

iOS的进程管理策略称为Jetsam,GitHub有人测试了其kill进程的优先级:

Jetsam优先级

二、Unity内存与GC

从Editor与Runtime比较,在Runtime时,只有Load资源才会影响内存,而Editor模式下,为了方便开发,只要打开Unity资源就会被加载(Unity打开很慢,2019.3的Asset Pipeline 2.0做了优化)。

2.1 Mono与IL2CPP的跨平台

Mono与IL2CPP是Unity的两种跨平台解决方案,目前官方推荐使用IL2CPP。

Mono跨平台流程

Mono的跨平台方案:编译器mcs将代码编译为IL,通过Mono运行时中的编译器将IL编译成对应平台的原生码。

Unity Mono是针对每个特定平台做了处理,因此才能跨平台。若出现新的硬件平台,则需要额外造轮子,其可移植性很差,因此Unity给出了IL2CPP方案。并且IL2CPP相比Mono有一定的性能提升。

IL2CPP方案流程(来自官方文档)

编译工程时,IL2CPP将Unity Scripting API 代码编译为常规 .NET DLL(托管程序集)。将所有托管程序集转换为标准C++代码。使用本机平台编译器编译生成的C++代码和IL2CPP的运行时部分。最后将代码链接到可执行文件或 DLL,具体取决于目标平台。

IL2PP相比于Mono,最大的变化在于由JIT编译变为了AOT编译。由此带来的变化体现在:(1)开发编译时间变长;(2)无法动态生成代码;(3)应用程序体积变小;(4)应用程序启动时间短。

在开发过程中可以选择Mono,提升开发效率,发布应用时使用IL2CPP得到更好的程序性能。

2.2 Unity VM GC

当Unity VM需要分配内存时,会检查当前内存。若内存足够时,可以直接分配内存,但内存不足时会触发GC,再次检测内存。若此时内存仍然不足,VM会向操作系统申请内存。

触发GC时,VM会暂停所有线程,可能引起程序卡顿。Unity采用了BOEHM处理GC,其为标记清除法。在标记阶段通过访问根节点,并遍历到叶子节点,最终将所有存在引用的内存都标记出来,清除未被标记的托管内存。

Unity的VM以Block管理内存,当一个Block连续6次GC没有被访问到(很难触发),这块内存会被返回给系统。

由于此种处理方式没有内存压缩,并且可能出现内存黑名单,因此容易出现内存碎片。在开发过程中,要尽量减少内存的申请,申请的内存尽量保持连续,对于资源加载应该优先加载较大的资源。

2.3 Unity内存分布

Unity内存分布

Unity内存分为Native堆内存、第三方库、虚拟机以及GfxDriver。Native堆内存中存储由Unity底层管理的数据,如音频、视频、Texture、Mesh、GameObject等。第三库常见的如tolua、Wwise。虚拟机通常指C#所产生的内存。GfxDriver是指当前驱动使用的Textures、RenderTargets、Shaders和Mesh数据内存。

三、Editor Asset

Unity 中的资源工作流程(来自官方文档)

Unity中的资源通常是指3D模型、音频文件、图像等用于程序使用的数据(代码数据也是一种资源)。程序开发阶段,将外部资源导入或复制到Asset目录下,Unity会监听到所导入的数据,并生成相应的Unity默认资源。

3.1 创建asset

Unity检测到新资源(文件夹)时会向此资源分配GUID,这是Unity在内部使用的ID,用于索引资源,以便Unity移动或重命名此资源不会破坏引用关系。

Unity对导入的外部文件格式不会进行修改,对内置格式资源(prefab/material/unity等),Unity以YAML格式进行存储。

prefab在Unity中的存储格式

文件前两行是文件格式版本注释,后续以--- !u!classID &fileID对组件数据进行标记。classID是Unity为组件类型分配的id,fileID为prefab中组件实例化的局部id,由此可以进行索引。上图GameObject挂载了3个组件,所以可以看到m_Component通过fileID映射到相应的组件实例。由于EventSystem是自定义组件,由此可以看到m_Script通过guid来引用到相应的代码资源。

由于这种格式化的存储方式,在非Unity Editor情况下处理或者查找带有特定参数的资源,可以通过纯文本替换或查找处理。(需要以下设置)

以文本格式存储序列化资源

3.2 监听资源导入

Unity提供了用于监听资源导入的基类,方便开发者对资源做标准化处理,具体基类如下:

来自Unity用户手册

3.3 资源处理

Unity在导入资源后,会在Library文件夹下生成真正用于Unity处理的资源。例如,Unity 将 .png 图像文件导入为纹理时,在运行时不会使用原始的 .png 格式数据,而是创建新的图形格式,将其存储在项目的Library文件夹中。Unity的Texture类会使用此导入版本,然后Unity将其上传到GPU进行实时显示。

除了Library,Unity会在Asset文件夹相同位置生成资源的.meta文件,用以记录资源设置参数与GUID。

meta文件

在Unity 2020以前的版本可以通过guid,在Library下搜索到Unity生成的资源。在Unity 2020之后的版本,会在Library下生成ArtifactDB和SourceAssetDB文件。

SourceAssetDB包含.meta相关数据(上次修改日期、文件内容哈希、GUID和其他元数据信息),由此判断是否需要重新导入资源。

ArtifactDB包含每个源资源的导入结果的信息。每个Artifact都包含导入依赖项信息、Artifact元数据信息和 Artifact文件列表。

从上述资源加载流程来看,项目中经常遇到资源引用丢失:(1)美术资源与meta没有一起上传,导致prefab无法通过guid找到资源。(2)美术替换资源时,先删除原有资源,再导入创建新资源,导致原有的prefab引用的guid失效。

对于漏传meta的情况,可在提交版本文件时做强制检测,若Asset下新增资源必须要有对应的meta文件。对于美术资源的替换,不能在Unity Editor下直接删除文件,需要通过import替换,或者在文件夹中替换资源再打开Unity。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Unity内存与资源管理 的相关文章

  • sql_model处理方案

    1 查询sql model的值 select sql mode 2 先贴一个大多数数据库的配置 STRICT TRANS TABLES NO ZERO IN DATE NO ZERO DATE ERROR FOR DIVISION BY Z

随机推荐

  • 算法题:(二分搜索)

    class Solution public int binarySearch vector
  • vue.js -- 动态组件&异步组件

    目录 动态组件 点击切换组件 优化点击切换组件 使用component标签优化代码 使用keep alive标签完善功能 异步组件 总结 动态组件 根据数据的变化 动态切换组件的显示 点击切换组件 首先定义两个子组件 子组件 app com
  • 读《游戏之旅--我的编程感悟》有感

    我不是学计算机的 但此书给我的感触颇深 此书成于2005年 我真希望自己能早6年读到这本书呀 2007年大学的时候就读到 作者叫云风 个人主页 www codingnow com 是个技术高手 网易游戏开发部门的重要人物 他书中有这样一段话
  • 【RabbitMQ教程】Work queues 工作队列模式

    目录 前言 Work queues工作模式介绍 消息模型 适用场景 消费策略 重要 消费策略选择 消费策略代码示例 轮询分发 1 定义生产者和消费者 2 运行程序 3 结果分析 公平分发 1 定义生产者和消费者 2 运行程序 3 结果分析
  • 憨批的语义分割3——unet模型详解以及训练自己的unet模型(划分斑马线)

    憨批的语义分割3 unet模型详解以及训练自己的unet模型 划分斑马线 学习前言 模型部分 什么是unet模型 unet模型的代码实现 1 主干模型Mobilenet 2 unet的Decoder解码部分 代码测试 训练部分 训练的是什么
  • 蓝桥杯-第六届蓝桥杯C语言A组/B组/C组-Python题解

    目录 方程整数解 星系炸弹 奇妙的数字 牌型种数 手链样式 饮料换购 奖券数目 三羊献瑞 加法变乘法 隔行变色 立方尾不变 方程整数解 方程 a 2 b 2 c 2 1000 这个方程有整数解吗 有 a b c 6 8 30 就是一组解 你
  • 猫眼美团滑块

    猫眼演场会下单会弹出美团的滑块验证码 使用js过滑块 想看演唱会但是又抢不到票 用python写一个猫眼自动下单
  • 2020年最常见的25个Web开发面试问题

    Java面试笔试面经 Java技术每天学习一点 Java面试 关注不迷路 作者 Team Codegiant 译者 王强 策划 李俊辰 本文最初发布于 Medium 网站 经原作者授权由 InfoQ 中文站翻译并分享 你把闹钟设定在了下午
  • 软件测试值不值得学,2023软件测试行情分析

    目录 1 人们的生活离不开软件 有软件的地方就有测试 2 测试工程师特别是自动化测试工程师的需求会越来越大 3 软件测试经验越丰富越受欢迎 不存在35岁限制 4 所有新兴行业比如chat gtp 车载系统等都需要测试工程师 薪资 就业 软件
  • Office2010安装步骤

    这是一篇我自己写于17年8月27日的office2010的安装教程 发现挺多人都不会安装或者激活 所以特地写了这篇文 安装office2010前请确保电脑中没有安装其它版本的office软件 否则可能造成两个版本的office不能正常使用
  • MATLAB:矩阵(基础知识)

    一 数组的创建和操作 1 矩阵的输入 gt gt A A gt gt B 6 5 3 B 6 5 3 gt gt C B C 6 5 3 2 调用矩阵 gt gt A 1 2 3 4 5 A 1 2 3 4 5 gt gt a1 A 1 访
  • kvm设置桥接网卡

    kvm默认的网卡模式为nat 虚拟主机可访问外网 但外部无法访问虚拟主机 将其改为桥接模式以实现内外互通 环境 centos6图形界面下 有virtual machine manager 程序 整个过程就两步 1 修改物理机网卡为桥接模式
  • SpringBoot报错:Cannot call isReadOnlyBeforeAttachedToSession when isReadOnlySettingAvailable == true

    错误后边会说明哪个实体类导致的 在实体类上加上 Proxy lazy false
  • Apache Beam实战指南

    https mp weixin qq com s biz MzU1NDA4NjU2MA mid 2247492538 idx 2 sn 9a2bd9fe2d7fd681c10ebd368ef81c9c chksm fbea5a75cc9dd
  • [原创]LoadRunner 12.02 录制脚本时提示无Internet访问,如何解决?

    在使用LoadRunner 12 02 进行录制脚本时提示无Internet访问 如下图 翻译中文如下 可以尝试以下方式解决 点击弹出框中的 Yes 即可 若还是有问题 尝试以下方式 1 LR12走的是证书机制 你按照我附件 图片1 中提供
  • springboot集成springsecurity + jwt的使用

    当项目中要用到用户的认证及权限的时候我们一般会使用 springSecurity来解决 引入 引入很简单
  • 学习若依框架----之----获取登录登录系统、ip、浏览器信息

    文章目录 1 导入需要用到的依赖 2 IP获取 3 AddressUtils 获取地址类 4 登录日志管理工具 4 SpringUtils获取bean工具 5 客户端工具 6 使用 7 测试 8 数据库记录 若依里面 创建登录日志是根据异步
  • USDT信用卡和转账入账接口

    class Usdtpay public function index data this gt request gt param uid data uid token data token type data type changeid
  • 经验模态分解(EMD)

    目录 1 背景 2 时间序列平稳性 3 EMD 方法 4 EMD 过程 5 EMD 方法的缺陷 6 Python 1 背景 实际工程测量中由于测量系统受外界环境影响经常在测量信号中产生趋势项 趋势项是指信号中周期大于采样长度的频率成分 通常
  • Unity内存与资源管理

    内存管理是程序开发的核心问题 而资源的使用又与内存息息相关 因此本章想要梳理整个开发流程中Unity对于内存与资源的管理方式 一 内存基础 1 1 基础概念 内存是暂时存放CPU中的运算数据 与硬盘等外部存储器交换的数据 在操作系统中 内存