Unity热更新那些事

目录

  • 热更新方案
  • Unity程序的两种编译方式
    • 编译阶段
    • 执行阶段
      • Mono方式
      • IL2CPP方式
      • 两种方式打包以后的项目目录结构
    • 其他
  • ILRuntime热更新
    • ILRuntime使用注意
    • ILRuntime的实现原理
    • ILRuntime的性能优化建议
    • ILRuntime的性能优化建议
  • HybridCLR热更新

参考链接
Unity热更新那些事
一小时极速掌握ILRuntime热更新
一小时极速掌握HybridCLR热更新

热更新方案

在这里插入图片描述

Unity程序的两种编译方式

  • Mono方式
  • IL2Cpp方式

编译阶段

执行:源码 -> 四个项目 -> 动态链接库(dll文件) -> CIL(通用汇编语言)
顺序:firstpass,Editor-firstpass->Editor,CSharp

动态链接库对应
Assembly-CSharp自己写的C#程序代码脚本
Assembly-CSharp-Editor编辑器相关脚本(需要创建“Editor”文件夹)
Assembly-CSharp-Editor-firstpass编辑器插件
Assembly-CSharp-firstpass插件(需要创建“Plugins”文件夹)

在这里插入图片描述

执行阶段

基本概念

  • CLR:通用语言运行平台(Common Language Runtime),是微软的.Net虚拟机
  • 主要作用:
    • 编译 – 运行前把C#编译为CIL
    • 运行 – 在运行的时候把CIL转换为各平台的原生码(安卓:ARM指令集,windows:x86、x64指令集)

在这里插入图片描述

Mono方式

  • 一个基于CLR的开源项目,允许引擎和用户的托管代码运行在每一个目标平台上
  • Mono支持的平台:Anfroid,Apple IOS,Linux,Windows等

跨平台原理

  • 把C#通过Mono complier(其他语言用的是Unity单独开发的一个Unity complier),编译为CIL语言
  • 各个平台下的Mono虚拟机,运行CIL语言,转换成原生码给CPU执行

Mono虚拟机如何运行CIL

  • JIT(Just In TIme)模式 – 在编译的时候,把C#编译成CIL,在运行时逐条读入,逐条解析翻译成原生码交给CPU再执行;
  • AOT(Ahead Of Time)模式 – 在编译成CIL之后,会把CIL再处理一遍编译为原生码,运行时交给CPU直接执行,Mono下的AOT只会处理部分的CIL,还有一部分CIL采用了JIT模式;
  • Full AOT模式 – 在编译为CIL之后,把所有的CIL编译为原生码,在运行的时候直接执行(ios平台只能使用这种)

IL2CPP方式

IL2CPP会在项目转成CIL之后,再把CIL转为CPP,然后在运行的时候把CPP加载进来,由各个平台的IL2PP VM转换为原生码

IL2CPP工作原理
使用IL2CPP开始构建时,Unity会自动执行以下步骤:

  • 将Unity Scripting API代码编译为常规.NET DLL(托管程序集)
  • 应用托管字节码剥离(此步骤可显著减小构建的游戏大小)
  • 将所有托管程序集转换为标准C++代码
  • 使用本机平台编译器编译生成的C++代码和IL2CPP的运行时部分
  • 将代码链接到可执行文件或DLL,具体取决于目标平台
    在这里插入图片描述

IL2CPP方式脚本编译流程

  • IL2CPP做的改变由下图红色部分标明
  • 在得到中间语言IL后,使用IL2CPP将他们重新变回C++代码,然后再由各个平台的C++编译器直接编译成能执行的原生汇编代码
    在这里插入图片描述

IL2CPP的优缺点

  • 优点
    • 运行速度快(CPP转原生码比CIL快)
    • 减少Unity公司的维护成本(Mono VM官方不支持这么多平台,所以很多平台的Mono VM都需要Unity自己维护,而C++编译器是各个平台现成的)
  • 缺点
    • 包体会变大
    • 编译速度慢
    • 不支持JIT

两种方式打包以后的项目目录结构

在这里插入图片描述

其他

IOS平台热更的困境

  • Unity只有IL2CPP模式的才支持64位系统,Mono不支持
  • 苹果在2016年1月要求所有新上架游戏必须支持64位架构
  • IOS系统禁止动态加载代码到内存并执行
    在这里插入图片描述

总结:C#脚本限制

  • IOS系统禁止动态加载代码到内存,并执行
  • 反射:
    • System.Reflection可用(只要编译器可以推断通过反射使用的代码需要在运行时存在)
    • System.Reflection.Emit命名空间中的任何方法不可用
  • 序列化:
    • 如果一个类型或一个方法仅通过反射被创建或被调用,则AOT编译器无法检测到需要为该类型或方法生成代码
  • 泛型虚方法:
    • 泛型虚方法由于在编译时类型不确定,编译器也不会在编译期生成针对特定类型的泛型方法调用

解决方案

采用解释执行语言,而非编译执行

  • Lua:Tolua/Xlua
  • C#:ILRuntime

ILRuntime热更新

官方文档

ILRuntime项目为基于C#的平台(例如Unity)提供了一个纯C#实现,快速、方便且可靠的IL运行时,使得能够在不支持JIT的硬件环境(如iOS)能够实现代码的热更新

ILRuntime使用注意

  • 跨域委托:需要额外添加适配器或者转换器
  • 跨域继承:如果想在热更DLL项目当中继承/实现一个Unity主工程里的类/接口,需要在Unity主工程中实现一个继承适配器,并注册
  • 反射转换:热更工程中的IL类型和C#类型系统不能混用,要类型映射后使用
  • CLR重定向
  • CLR绑定

ILRuntime的实现原理

  • ILRuntime借助Mono.Cecil库来读取DLL的PE信息,以及当中类型的所有信息,最终得到方法的IL汇编码,然后通过内置的IL解译执行虚拟机来执行DLL中的代码
  • 为了高性能进行运算,尤其是栈上的基础类型运算,如int,float,long之类类型的运算,直接借助C#的Stack类实现IL托管栈肯定是个非常糟糕的做法。因为这意味着每次读取和写入这些基础类型的值,都需要将他们进行装箱和拆箱操作,这个过程会非常耗时并且会产生巨量的GC Alloc,使得整个运行时执行效率非常低下
  • 因此ILRuntime使用unsafe代码以及非托管内存,实现了自己的IL托管栈。

ILRuntime的性能优化建议

  • Release模式下进行性能测试
  • 关闭Development Build选项来发布Unity项目
  • 避免GC:
    • ILRuntime跨域调用默认采用反射,这种方式少用,多用CLR绑定或基于InvocationContext的调用
    • 基于IL托管栈重新实现值类型的代码绑定(使用unsafe代码以及非托管内存)
    • 频繁调用的方法(例如Update方法)上避免使用params可变参数列表(会new数组出来)

ILRuntime的性能优化建议

  • 不依赖MonoBehaviour的代码框架
  • 自动化CLR绑定代码生成
  • 与Addressable资源管理和热更系统的结合

HybridCLR热更新

官方文档

  • HybridCLR是一个特性完整、零成本、高性能、低内存的近乎完美的Unity全平台原生c#热更方案。

  • HybridCLR扩充了il2cpp的代码,使它由纯AOT runtime变成AOT+Interpreter 混合runtime,进而原生支持动态加载assembly,使得基于il2cpp backend打包的游戏不仅能在Android平台,也能在IOS、Consoles等限制了JIT的平台上高效地以AOT+interpreter混合模式执行,从底层彻底支持了热更新。

  • HybridCLR不仅支持传统的全解释执行模式,还开创性地实现了 Differential Hybrid Execution(DHE) 差分混合执行技术。即可以对AOT dll任意增删改,会智能地让变化或者新增的类和函数以interpreter模式运行,但未改动的类和函数以AOT方式运行,让热更新的游戏逻辑的运行性能基本达到原生AOT的水平。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/182992.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pda条码二维码扫描数据采集安卓手持终端扫码热敏标签打印一体机

HT800新一代移动物联终端是深圳联强优创信息科技有限公司自主研发的基于Android11操作系统的高性能、高可靠的工业级手持数据终端,能与其它设备进行无线通讯,提供良好的操作界面,支持条码扫描、RFID读写(NFC)、GPS定位…

Android 扩大View可点击区域范围

有时候会遇到这种需求:本身控件显示在很小的范围内,但是要求扩大可点击的区域。根据官方文档https://developer.android.com/develop/ui/views/touch-and-input/gestures/viewgroup?hlzh-cn#delegate可以得知通过 TouchDelegate 类,让父视图…

【复盘】记录一次JVM 异常问题 java.lang.OutOfMemoryError: unable to create new native thread

背景是最新运营提了一个需求,需要根据用户信息拉去三分机构的信贷数据,需要达到一天百万级别,但是经过实际测试,也只能达到40W量级,具体就是通过起多个Spring Boot项目,每个项目1S拉一个用户,基…

使用 Rust 进行程序

首先,我们需要安装必要的库。在终端中运行以下命令来安装 scraper 和 reqwest 库: rust cargo install scraper reqwest 然后,我们可以开始编写程序。以下是一个基本的爬虫程序,用于爬取 上的图片: rust use reqwe…

接口自动化测试分层设计与实践总结01

本文以笔者当前使用的自动化测试项目为例,浅谈分层设计的思路,不涉及到具体的代码细节和某个框架的实现原理,重点关注在分层前后的使用对比,可能会以一些伪代码为例来说明举例。 接口测试三要素: 参数构造 发起请求&…

C#,数值计算——偏微分方程,Relaxation的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { public class Relaxation { private Relaxation() { } public static void sor(double[,] a, double[,] b, double[,] c, double[,] d, double[,] e, double[,] f, double[,] u, double rjac) …

Python基础(第五期): python数据容器(序列) 列表 集合 元素 字符串 字典 序列遍历操作

python基础专栏 python基础(第五期) 文章目录 python基础(第五期)数据容器一、列表1、列表的定义2、列表的下标索引 3、列表的(添加)方法3.1 列表的查询方法3.2 修改特定下标索引的值3.3 列表指定位置插入元素3.3 列表指定元素的追…

Elasticsearch:搜索架构

Elasticsearch 全文检索的复杂性 为了理解为什么全文搜索是一个很难解决的问题,让我们想一个例子。 假设你正在托管一个博客发布网站,其中包含数亿甚至数十亿的博客文章,每个博客文章包含数百个单词,类似于 CSDN。 执行全文搜索…

【Unity细节】为什么UI移动了锚点,中心点和位置,运行的时候还是不在设置的位置当中

👨‍💻个人主页:元宇宙-秩沅 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 秩沅 原创 😶‍🌫️收录于专栏:unity细节和bug 😶‍🌫️优质专栏 ⭐【…

数据约束及增删改查(CRUD)进阶-MySQL

文章目录 一、数据库约束1.1 约束类型1.2 NULL约束1.3 UNIQUE:唯一约束1.4 DEFAULT:默认值约束1.5 PRIMARY KEY:主键约束1.6 FOREIGN KEY:外键约束1.7 CHECK 约束(了解) 二、表的设计2.1 一对一2.2 一对多2…

kimera论文阅读

功能构成: Kimera包括四个关键模块: Kimera-VIO的核心是基于gtsam的VIO方法[45],使用IMUpreintegration和无结构视觉因子[27],并在EuRoC数据集上实现了最佳性能[19]; Kimera-RPGO:一种鲁棒姿态图优化(RPGO)方法,利用现代技术进…

代码随想录 Day38 完全背包问题 LeetCode T70 爬楼梯 T322 零钱兑换 T279 完全平方数

前言 在今天的题目开始之前,让我们来回顾一下之前的知识,动规五部曲 1.确定dp数组含义 2.确定dp数组的递推公式 3.初始化dp数组 4.确定遍历顺序 5.打印dp数组来排错 tips: 1.当求取物品有限的时候用0-1背包,求取物品无限的时候用完全背包 结果是排列还是组合也有说法,当结果是组…

vue 实现在线预览Excel-LuckyExcel/LuckySheet实现方案

一、准备工作 1. npm安装 luckyexcel npm i -D luckyexcel 2.引入luckysheet 注意:引入luckysheet,只能通过CDN或者直接引入静态资源的形式,不能npm install。 个人建议直接下载资源引入。我给你们提供一个下载资源的地址: …

JVM虚拟机:垃圾回收器之Parallel Scavenge

本文重点 在前面的课程中,我们学习了新生代的串行化垃圾回收器Serial,本文我们将学习新生代的另外一个垃圾回收器Parallel Scavenge(PS),PS是一个并行化的垃圾回收器,它使用复制算法来清理新生代的垃圾。 运行方式 如上所示,当进行垃圾回收的时候,它会暂停工作线程,而…

【图像分类】【深度学习】【Pytorch版本】AlexNet模型算法详解

【图像分类】【深度学习】【Pytorch版本】AlexNet模型算法详解 文章目录 【图像分类】【深度学习】【Pytorch版本】AlexNet模型算法详解前言AlexNet讲解卷积层的作用卷积过程特征图的大小计算公式Dropout的作用AlexNet模型结构 AlexNet Pytorch代码完整代码总结 前言 AlexNet是…

Mac电脑录屏软件 Screen Recorder by Omi 中文最新

Screen Recorder by Omi是一款屏幕录制软件,它可以帮助用户轻松地录制屏幕活动,并将其保存为高质量的视频文件。 该软件提供了多种录制选项,包括全屏录制、选择区域录制和单窗口录制等,同时提供了丰富的设置选项,如视…

数据集划分:手动划分文件夹中的图片数据集为训练集、验证集和测试集

1.需求 手动划分文件夹中的图片数据集为训练集、验证集和测试集,即进行文件夹中的数据集(都是图片)进行划分。 2.步骤 使用文件处理库(如os)遍历读取文件夹中的图片文件。将读取到的图片文件路径存储到列表中。打乱…

Golang源码分析之golang/sync之singleflight

1.1. 项目介绍 golang/sync库拓展了官方自带的sync库,提供了errgroup、semaphore、singleflight及syncmap四个包,本次分析singlefliht的源代码。 singlefliht用于解决单机协程并发调用下的重复调用问题,常与缓存一起使用,避免缓存…

〔001〕虚幻 UE5 安装教程

✨ 目录 🎈 下载启动程序🎈 注册个人账户🎈 选择引擎版本🎈 选择安装选项🎈 虚幻商城的使用🎈 每月免费插件🎈 安装插件🎈 下载启动程序 下载地址:https://www.unrealengine.com/zh-CN/download点击上面地址,下载 UE5 启动程序并安装🎈 注册个人账户 打开商…