ToLua的释放时机

ToLua的释放时机

这是第172篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间20分钟,认真读完必有收获。

UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)


本期目录:

  • ToLua的释放时机
  • Physics.Proccesing和Physics.Simulate的区别
  • 打包出来包含图片UnitySplash-cube
  • 采用LZ4把资源打成大包与打成小包在内存占用的区别
  • 如何解决Bundle文件内对其它Bundle的依赖顺序

Lua

Q:使用UWA GOT测试游戏挂机的Mono内存增长情况。发现LuaInterface.LuaFileUtils:ReadZipFile这里常驻的内存一直在增加。

这里每隔一段时间就会调用LuaInterface.LuaFileUtils:ReadZipFile的原因是:在Lua代码中会定时清理游戏配置,package.loaded也设为NIL。下一次需要用到配置的时候重新require。

求助的问题:ToLua虚拟机在require载入代码后,什么时候会去检查释放内存?多次require同个代码文件会造成内存泄漏吗?

A:根据你提供的信息建议你的查找方向:
(1)是不是重写了require;
(2)是不是读文件函数本身的问题。

static int ll_require (lua_State *L) {
  const char *name = luaL_checkstring(L, 1);
  lua_settop(L, 1);  /* _LOADED table will be at index 2 */
  lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
  lua_getfield(L, 2, name);  /* _LOADED[name] */
  if (lua_toboolean(L, -1))  /* is it there? */
    return 1;  /* package is already loaded */
  /* else must load package */
  lua_pop(L, 1);  /* remove 'getfield' result */
  findloader(L, name);
  lua_pushstring(L, name);  /* pass name as argument to module loader */
  lua_insert(L, -2);  /* name is 1st argument (before search data) */
  lua_call(L, 2, 1);  /* run loader to load module */
  if (!lua_isnil(L, -1))  /* non-nil return? */
    lua_setfield(L, 2, name);  /* _LOADED[name] = returned value */
  if (lua_getfield(L, 2, name) == LUA_TNIL) {   /* module set no value? */
    lua_pushboolean(L, 1);  /* use true as result */
    lua_pushvalue(L, -1);  /* extra copy to be returned */
    lua_setfield(L, 2, name);  /* _LOADED[name] = true */
  }
  return 1;
}

这个xLua中require的函数实现,如果你没有重写require函数,那么这个函数就相当于:

local _loaded = {}
function require(name)
    local tab = _loaded[name]
    if tab then
        return tab
    end
    --下面是伪代码
    local bytes = LuaInterface.LuaFileUtils:Loaded(name)
    tab = lua.LoadModule(bytes)
    _loaded[name] = tab
    return tab
end

感谢shunfy@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5d51505e80d96a06d776dc52


Physics

Q:我在UWA报告中的重要参数解析那里看到Physics.Proccesing和Physics.Simulate,看到它们的调用情况一致,但是耗时不一致?请问这两者的区别是什么?分别代表什么意义?优化的时候侧重点是什么呢?


A:这两者都是Unity引擎中PhysX物理引擎的耗时开销。两者调用次数一致是正常的,因为它们确实每帧中都同时调用。对于它们具体分别负责哪些地方,我并没有看过PhysX的源码,所以无法回答,但可以说明的是,在Unity 2017之前,Physics.Simulate是物理模块最主要的耗时函数,而在Unity 2017之后,Physics.Processing是物理模块最主要的耗时函数。

关于优化,可以查看这两个问题帖子:

《Physics.Processing占用过大》
《在游戏里没有使用物理(Physics)相关功能时,怎么把物理相关的性能消耗降到最低(大部分是Physics.Processing)》

该回答由UWA提供,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5d4ee389c494b506d267394c


Resource

Q:用AssetStudio解包自己游戏打出来的包,发现包里有UnitySplash-cube这张图片,Unity版本是2017.4.10,也找不到哪里用了,求问怎么能去掉它?

看了一下它是在Unity default resources这个文件里,这里面除了这个还有好几个没用的图片和Unity自带的Mesh,有办法去掉那些没用的吗?



A:这个问题以前还真研究过,当然后来不了了之了。个人觉得理论上可行的步骤如下:
(1)在Unity安装目录Editor/Data/Resources下找到unity default resources文件,拷贝一份出来。
(2)将拷贝出来的文件添加后缀.asset,然后将其放到项目工程里面,没错,这个unity default resources其实就是一个Binary模式序列化的YAML文件。如下图:

(3)利用AssetDataBase提供的API删除不需要的资源,确保序列化为Binary模式,保存修改后的文件。
(4)将修改后的文件去掉后缀,替换安装目录下面的自带文件,重启Unity。

其中步骤(3)、(4)没有动手实践,可能有些问题,比如:资源的GUID发生变化导致无法关联等等。题主可以先实践一下看看。

其实除了unity default resources,还有两个文件也是如此,不过文件很大导入Unity会导致假死:

感谢张迪@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5d525d9d80d96a06d776dc53


Bundle

Q:如果不考虑热更大小,把资源打成几个大的AssetBundle包采用LZ4,是否与打成小包在内存使用上没有区别?

https://answer.uwa4d.com/question/5ae13b610956834900752617

文档上说chunk存储,在Load Asset时,才会读取相应资源到内存。这样把资源压到一个大包和分包在内存占用上没有区别吗?另外,读多个包效率会比读单个效率低吗?

A1:(1)内存占用有区别,但是差别不大。

使用LZ4压缩格式,包含的资源数量越多头文件内存占用越大,理论上可以通过优化资源路径长度来削减占用(作为参考,我们项目把所有材质打成了一个Bundle,资源数量7000+,占用内存为2.5MB);

(2)因为有IO消耗,多个包的加载效率会比单个包低。
感谢于翔@UWA问答社区提供了回答

A2:(1)这个问题其实和你使用LZ4或者LZMA关联不大,资源应该还是需要按功能模块或者其它更高效的方式划分。假若A模块和B模块毫不相干,就没必要把它们放在一个Bundle里面了,毕竟Bundle越大序列化需要的时间就越长,占用的内存也就越大;反之,则加载时间变短,且减少内存占用。

(2)如果是for循环一个一个的LoadAsset那肯定不如LoadAllAsset来得快;但如果是Bundle的层次而非Bundle中的Asset,那只能一个一个Bundle的来,谈不上什么效率。

感谢李星@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5d529f5180d96a06d776dc54


Bundle

Q:如何解决Bundle文件内对其它Bundle的依赖顺序,导致不同build之间MD5变化。不同时间或机器打出来的Bundle二进制有细微差别,解出来对比如下,即对其它Bundle的依赖顺序不一样了,有什么办法能保证顺序?


A1:(1)有Unity源码,重写依赖排序算法。
(2)尝试使用AssetStudio重排依赖顺序。
(3)自定义MD5计算规则,例如:资源+meta的MD5。
感谢张迪@UWA问答社区提供了回答

A2:(1)自己算MD5;
(2)发现在有之前AssetBundle包的情况下,和删除重新打,有时候打出来的AssetBundle包会不一样,于是改成每次删除所有AssetBundle包重新打;
(3)后来又发现,改了某些资源后,“导入资源后立刻打包”与“导入资源后关掉Unity重开再打包”出来的AssetBundle包也会不一样。这次改成SVN更新好之后,先打开一次让Unity导入资源,然后关掉Unity重开再打包。
感谢deviljz@UWA问答社区提供了回答

A3:可以结合自己项目的热更新和资源管理系统自行实现一套类似的配置,保存游戏中资源和Bundle的相关信息。

感谢范君@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5d560f0ec494b506d26739e8

封面图来源于网络


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA学堂:edu.uwa4d.com
官方技术QQ群:793972859(原群已满员)