热更新、AB包、Lua面试题
原文链接:https://blog.csdn.net/qq_43282959/article/details/109719916
原文链接:https://blog.csdn.net/weixin_56130753/article/details/140177017
https://zhuanlan.zhihu.com/p/719081492
AB包的本质与优势
本质:AB包是Unity提供的资源打包格式,将资源(预制体、纹理、场景等)编译为二进制文件,支持动态加载。
优势:
热更新:无需重装应用即可更新资源。
按需加载:减少首包体积,优化内存占用。
资源隔离:避免Resources文件夹的强耦合性。
如何解决AB包不允许重复加载的问题?
1、建立AB包缓存字典(核心方案!!!):使用字典缓存已加载的AB包,避免重复加载。
好处:避免重复加载导致的报错,减少内存开销和加载耗时。
2、热更新时远程AB包与本地包同名但内容不同(如热更新版本迭代),需额外处理:
- 组合URL与包名作为唯一键,URL哈希表区分;
- 排队加载与延迟卸载,避免连续加载同名AB包时的冲突。
热更分成2部分
导出热更资源
游戏流程热更
1、导出热更资源
打包热更资源的对应的md5信息(涉及到增量打包)
上传热更ab到热更服务器
上传版本信息到版本服务器
2、游戏流程热更
启动游戏
根据当前版本号,和平台号去版本服务器上检查是否有热更
从热更服务器上下载md5文件,比对需要热更的具体文件列表
从热更服务器上下载需要热更的资源,解压到热更资源目录
游戏运行加载资源,优先到热更目录中加载,再到母包资源目录加载
Lua如何与C#进行交互的
答: Lua调用C#:
1.打标签[LuaCallC#]:首先生成C#源文件所对应的Wrap文件,由Lua文件调用Wrap文件,再由Wrap文件调用C#文件;
2.不打标签:通过反射方式当索引系统API、dll库或者第三方库时,如果无法将代码的具体实现进行代码生成,可采用此方式实现交互。缺点:执行效率低。
C#调用Lua:打标签[C#CallLua]:由C#先将数据放入栈中,由lua去栈中获取数据,然后返回数据对应的值到栈顶,再由栈顶返回至C#。
C#生成Bridge文件,Bridge调dll文件(dll是用C写的库),先调用lua中dll文件,由dll文件执行lua代码
C#->Bridge->dll->Lua OR C#->dll->Lua
Lua如何在项目中使用:
答:通过一个C#脚本调用 Lua入口文件(Main.lua),加载全局模块,比如UI模块,事件模块,table工具类模块,class类模块,单例管理类模块等等,部分模块用C#实现,Lua调用C#
1、Lua热更
文件时,文件是重写的,还是只写一部分?
热更分为资源更新和代码更新,资源更新的颗粒度是基于ab包的,是基于一个个资源包来进行下载和替换。做代码热更新的时候,如果热更代码被打入了ab包,那么下载的时候,也是整个代码所在的ab包一起下载。如果热更代码是单独部署的,我们就可以基于对应的文件颗粒度来下载替换。一般做lua热更新的时候,代码打成ab包后,可能只有几百k,并不很大,那么我们打一个ab包就可以了。如果lua代码打包成ab包后很大,我们可以考虑把lua代码分成几个ab包,这样下次热更的时候,就是基于lua代码所在的ab包来热更。对于其它热更技术也类似。热更代码是打一个ab包,还是打多个ab包,完全取决于代码ab包的大小;
2: lua是怎么热更的?
step1:lua做热更时,通过版本对比,md5文件差异比较,把更新的lua代码所在的ab包下载下来;
step2: 当最新代码下载下来以后,我们首先去下载目录下加载lua代码所在的ab包,如果没有,就到本地StreammingAssets
目录下加载,如果没有,就报错。
step3: Lua 虚拟机添加 customloader, 当有require来加载lua代码的时候,我们就从来到 customloader的函数,这个函数从Lua代码所在的ab包里面,根据
lua文件路径,把文本资源读出出来,并装载到lua虚拟机里面执行。
由于每次都是优先从下载目录下加载lua, ab包,所以热更的时候,能加载执行到最新代码。
3:Lua语言中 require的顺序是怎样的
step1:这个是require的语法,首先是lua虚拟机从文件中读取lua代码,
step2: 把lua代码装在进lua虚拟机;
step3: 执行lua代码里面的代码指令和函数调用;
step4: 如果有return, 返回结果;
step5: 如果重复require, 就只会执行里面的函数调用与代码指令,不会反复的装载;
4、说说lua的传值与传引用
lua分成基本的数据类型和引用对象数据类型:
字符串,表,数组,属于引用类型,变量保存的是它对象的引用,我们通过引用访问它;
数字,bool值等基本数据类型,变量直接存储他们的数据;
对于基本数据类型而言,赋值语句就是数据copy;
对于引用数据类型而言,赋值语句,就是让这两个变量指向同一个内存对象;
5: 垃圾回收机制
(C# Lua)
Lua虚拟机
内置了自己的垃圾回收机制和接口,我们在封装lua虚拟机的时候,需要在特定的时候,来调用,Lua的gc接口来回收相关的垃圾,一般我们会在Lua虚拟机封装的时候,在c# 的update里面,设定一些lua垃圾回收的触发条件,比如,每隔100ms调用一次gc, 回收一次等,具体的策略,可以根据实际情况来定。同时lua可以允许开发者自己在特定的时机来调用垃圾回收。
lua的GC
Lua 的垃圾回收(GC,Garbage Collection)机制是为了自动管理内存,确保不再使用的对象能被及时回收,避免内存泄露。Lua 使用了一种结合引用计数和周期性标记-清除(mark-and-sweep)算法的混合策略。下面是 Lua GC 的几个关键方面:
引用计数(Reference Counting):
Lua 对象(如 tables 或 userdata)有一个内部计数器,用于跟踪有多少地方引用了这个对象。当引用计数降为零时,对象被认为不再被使用,可以被立即回收。这种方式可以快速回收不再需要的对象,但引用计数器并不能处理循环引用的情况。
周期性标记-清除(Mark-and-Sweep):
为了解决引用计数无法处理循环引用的问题,Lua 会周期性地执行一个标记-清除的垃圾回收过程。这个过程分为几个阶段:
标记(Marking):从根集(Root Set)开始,这包括全局变量、正在执行的函数的局部变量、栈上的变量等。GC 会遍历这些根集中的所有引用,将可达的对象标记为“存活”。
清除(Sweeping):未被标记的对象被认为是垃圾,将被回收。在清除阶段,Lua 会遍历内存,收集所有未标记的对象。
重新标记(Remark):在标记阶段之后,所有对象都会被标记为未扫描(unscanned)。这是为了避免在标记和清除过程中对象被新创建的引用改变状态。
增量式垃圾回收(Incremental GC):
Lua 的 GC 还采用了增量式的回收方式,这意味着 GC 的工作可以被分割成多个小步骤,每个步骤只处理一部分工作,这样可以减少 GC 的停顿时间,避免长时间的“stop-the-world”现象,提高程序的响应性。
阈值触发(Threshold Triggers):
Lua 的 GC 并非在每次分配内存时都运行,而是根据预设的阈值来决定何时启动。当分配的内存达到一定的比例时,Lua 会触发 GC 过程。这个阈值可以通过 Lua 提供的 collectgarbage(“setpause”) 和 collectgarbage(“setstepmul”) 函数来调整。
弱引用(Weak References):
Lua 支持弱引用,这意味着可以创建一个不增加引用计数的引用。弱引用常用于创建不会阻止其他对象被垃圾回收的缓存或映射表。
析构器(Destructors):
Lua 允许为 userdata 定义析构函数,当 userdata 被垃圾回收时,析构函数会被自动调用,这可以用来清理任何与 userdata 关联的外部资源。
6、垃圾回收造成卡顿,怎么办
当某个时候,有大量的垃圾需要回收的时候,会由于gc所造成卡顿。这个时候,我们能做的就是回收一部分,另外的部分后面去回收,将gc回收的时机,不断地延后,平均到某个update里面,使得过度地时候帧率更加地平滑。这个时候我们需要留意在GC高峰期,来做一些事情,比如,场景地图切换地时候,这个时候容易引发gc高峰,时刻监测,如果发现切换高峰地时候GC造成的卡顿,我们就可以按照上面的思路来处理,主要是减少每次GC的量,延迟GC到后面的update,避免波峰的冲击。
7:说说你们项目中的战斗系统
的架构与设计:
做战斗系统和架构的时候,我们一般把代码逻辑分成3层来设计,同时把数据独立出来,我们的项目设计如下,不同公司可能不一样,我们之前公司是这样做的:
1: 我们会把战斗中的功能,做成组件,比如,动画切换,伤害计算等; 我们叫做功能层;
2: 我们会把战斗单元做一个组件,比如Charactor, 然后让Charactor来has 功能组件,并在Charactor中提供标准的通用的策略,比如,行走,技能释放等; 同时不是的角色,我们会编写Player, Enemy等来继承自Charactor,并绑定对应角色的战斗数据,用战斗数据来驱动统一的逻辑;
3: 操作层:我们会把战斗中的操作独立出来,比如UI操作,网络事件,AI事件等,通过事件模块,来调用到战斗中的具体策略,这样,可以实现不同操作层来驱动战斗,调用战斗策略;
4: 战斗中的数据,我们一般都用excel表格来给策划填写,更具策划的游戏需求来制定好对应的数据格式。如果有必要,还可以做一些可视化工具(技能编辑器),来给策划使用,最后导出战斗数据。
5: 技能编辑器:可视化的制定技能的一些数据,比如buff时间,攻击时间,等具体要根据游戏需求来定;
更多推荐


所有评论(0)