声明:
这里仅凭个人理解和记忆印象随笔记录,用于辅助理解生涩难懂的更专业原理表述;
忽略术语不准确或错误对应情况。
可以指正,补充,可以选择不看,纯个人理解,拒绝苛责!!!
————————————
Lua 是一种轻量脚本语言,解释性语言,类似于js,h5很容易就可以执行
相对c#,java这种写好程序后,还要编译,解释器解析成底层c++,最后转成机器语言,执行,就很麻烦
由于语言特性,lua就跳过中间编译解析处理过程,在执行语句时,根据fix标签这种,插入到对应位置,替换执行的功能逻辑,进而实现功能热更
————————————
再细节明确的,
首先语言特性
lua是一种轻量级、解释型脚本语言,还具有动态加载和运行时修改代码的能力。这导致它有支持热更能能力。
**解释型语言**:
Lua 代码不需要预编译,
运行时通过 Lua 虚拟机(LVM)逐行解释执行。
所以,修改后的 Lua 脚本可以直接被加载和运行,无需重启程序。
(每次改过脚本后,unity都得重新编译下重新运行,lua的话,就是你运行着unity,把lua丢给它,它就直接把lua执行了)
- **动态加载**:
Lua 支持在运行时动态加载代码文件
(如通过 `require` 或 `dofile`),甚至可以替换已有的函数或模块。
- **灵活性**:Lua 的弱类型和动态特性使得代码修改后不需要重新编译整个项目,只需替换脚本文件即可。
这个灵活性可以结合反射原理来理解,动态加载,可以结合多态的执行来理解
运行时,根据程序执行不同脚本,同个方法执行不同效果功能,运行时根据执行到哪里,来确定变量的类型,不需要写lua时确定变量的类型。
所以说是灵活,弱类型,简单写几个lua脚本项目,也使用过c#的引用类型和重载重写,对比下应该能理解。
—————————————
对比unity,C#的底层执行过程
C# 是编译型语言,
编译编译嘛,先编写打包,然后到合适位置再解析执行。
代码在打包时会被编译成 IL(Intermediate Language),一种中间语言
中间语言最后在运行时,通过 JIT(Just-In-Time)编译为机器码。
机器码就理解成类似10101011这种,机器/底层c++能直接执行的数据
lua是解释性语言,就没有打包编译解析的过程,就直接丢给机器,机器就能直接读懂运行
(不专业的说,就是这个意思)
那个unity项目会用到各种程序集/功能库,比如unity.engine,system,unity.engine.ui,其实就是一个个打包好的c#的程序包/dll,
我们有时候用的资源插件package包,也是一类的,和项目工程来说,就是一个大包,一个小包
unity通过程序引用,或者反射来调用。但都是停止运行后,把这个库加进去后,运行时再引用到,再能执行。因为要编译解析过程
上面这些大概了解lua热更脚本和正常项目程序之间区别,也要注意中间提到的反射
unityc#通过反射在运行时来调用不同的库,程序集,通过反射确定正在运行的对象变量是什么类型之类的
因为表面我们写代码,定义变量是啥类型,用到那个库,而底层有个元数据的东西,有记录各个对象的数据信息,反射就是读这个元数据,跨程序集,找到这是啥玩意,然后来告诉你。
专业术语太难记了,可能会有出入,原理可以这样理解
——————————
再补充点计算机程序执行的底层过程,有点属于机组操作系统或编译原理方面的,就是机器执行程序那部分的,配合着理解
程序的底层执行过程一般包括以下几个主要阶段:
1、编译
编译器将源程序,检查和处理,如检查有哪些关键词,语法对不对等,
将整块的程序,分析转换为目标机器的指令序列,
也就是一条条待执行处理的指令
2、加载
- 操作系统的加载器,将程序的代码和数据(也就是上面的一条条指令和使用的数据)从磁盘加载到内存中
3、执行
(就是是内存cpu处理一条条指令和数据的过程)
(1) 取指:CPU的控制器从内存中读取指令,将其放入指令寄存器。
(2)译码:指令译码器对指令进行分析,确定指令的操作码和操作数等信息
(也就是要做什么操作,加减乘除啊,操作的数据是那些啊)
(3)执行:运算器根据译码结果进行相应运算操作
(就是机器使用加法器,乘法器,按上一步译码结果处理数据得到结果的过程)
(4)访存:
若指令涉及访问内存数据,CPU会根据指令中的地址信息进行内存读写操作。
(也就是操作过程要执行啥东西,但东西还不在cpu里,就去磁盘里找一下)
(5)写回:将执行结果写回到寄存器或内存中。
可以把这个程序执行过程,结合上面lua和c#程序执行过程,理解一下
(那个我是用大白话解释了一下,可能不太准确,用来理解还行)
——————————
然后可以再回过头来再看两种语言执行过程,就没那么难理解了:
C# 代码 → C# 编译器 → IL(中间语言) → JIT/AOT 编译 → 机器码
Lua 代码 → Lua 虚拟机(LVM) → 逐行解释为操作码(OpCode) → 调用宿主语言(如 C)实现的功能
JIT(Just-In-Time):
运行时动态编译 IL 为机器码(如 PC/Android)。
AOT(Ahead-of-Time):
预先编译为机器码(如 iOS 的 IL2CPP)。
Lua 虚拟机(LVM):
模拟 CPU 的行为,通过寄存器式虚拟机或 栈式虚拟机执行操作码。
Mono/.NET 运行时:
默认的 C# 执行环境,包含 JIT 编译器(Android/PC)或 AOT(iOS)。
IL2CPP:将 IL 转换为 C++ 代码,再编译为原生机器码,
解决iOS 的 JIT 限制(应该是iso不支持JIT编译器。支持ATO)
————————————
上面这些大概理解了,后面再看别人写的专业术语很多的解释,应该就没那么难理解了