导读

随着Lua在项目中的大量使用,它所带来的性能问题也逐步成为了项目运行时的重大性能瓶颈之一。特别是内存相关的性能问题,无论是内存分配过大还是内存泄露无法回收,目前都已经在不少研发项目中集中爆发。

UWA推出的GOT Online中的Lua模式已经慢慢成为研发团队对Lua进行日常性能监控的有效手段。因此,也有越来越多的团队反馈,在监控到table数持续上涨,引用Mono对象持续增多等等问题时,应该如何快速地解决?

本次博物纳新推荐的开源库项目:LuaProfiler-For-Unity,相信可以帮助到大家。
Lua Profiler For Unity支持XLua、SLua、ToLua,该工具是基于远程Socket的Profiler工具,因此它支持Android,iOS的真机Profiler。

小编将结合实际项目中遇到的问题,为大家介绍这款开源库的用法。

开源库链接:https://lab.uwa4d.com/lab/5bf38db072745c25a80c1276

作者Blog:https://www.zhihu.com/people/ElPsyConGree/activities


操作流程

一、部署和安装
参考项目中的Readme文档阐述的详细流程:
1、打开两个Unity项目,一个放进游戏客户端,一个用于展示数据
2、打开LuaProfiler文件夹


LuaProfiler文件目录

3、将 LuaProfilerClient 文件夹复制到游戏项目内,如果您的C#Lua脚本位于Plugins文件夹中,则将 LuaProfilerClient 复制到插件。此工具必须确保该代码必须位于具有C#Lua代码的同一DLL中。
4、使用 Unity5.6 or newer version Unity版本将 LuaProfilerServer 作为Unity项目打开
5、如果Unity版本低于5,请在开始游戏前调用以下代码。

MikuLuaProfiler.HookLuaSetup.OnStartGame();

注意:不要在static变量声明里面启动Lua流程(比如XLua的Demo),请在Awake或者Start里面进行调用。

二、使用教程
(该小节内容全部来自于项目Readme文档,想要阅读更详细教程的读者可访问项目主页:https://lab.uwa4d.com/lab/5bf38db072745c25a80c1276)

1、配置客户端

Lua Profiler Client界面

LuaProfilerClient插件所在的游戏项目工程,通过Editor界面的Window->Lua Profiler Window打开客户端设置界面。选择想要分析器的代码类型,C#代码颜色为绿色,Lua代码颜色为蓝色。

2、配置服务器端
LuaProfilerServer插件所在的项目工程,通过Editor界面的Window->Lua Profiler Window打开服务器数据显示界面。

Lua Profiler Server界面

单击OpenService,等待客户端连接。

操作流程示意图

3、相关功能操作

使用示意图

3.1 相关基础数据统计
折线走势图展示了PSS、Mono内存、Lua内存、FPS的走势:

折线走势图

数据列表

数据列表中列举了当前帧下图所示的相关数据:

3.2 监控注册表

注册表引用的Lua对象统计

此处区域会显示当前被注册表引用的类型为Function和table的Lua对象。

3.3 Diff两个不同时期的Lua变量
选取一个适当的时机,比如配置表加载完后,准备打开一个新的UI的时候点击MarkLuaRecord按钮。

操作步骤

打开UI然后关闭并卸载掉UI资源,点击DiffRecord,工具将会对Mark时候的Lua变量与DiffRecord时候的变量进行差异比较。

数据显示界面

点击ShowLog按钮,将会把文件存盘打开之后将把对于变量的类型以及引用路径打印出来。注意_G表示全局表,_R表示被C#引用的对象。

引用链

3.4 Destroy null values统计
该模块展示了Unity已经将资源释放,而Lua仍然引用的变量。

引用链

功能原理详解

一、相关基础数据统计
查看这部分数据时,除了关注排序中开销较大、内存占用较高的函数外还可以关注一些重要的字段,例如:

require字段,比较普遍的性能问题在于:加载配置表时产生一个内存占用较大的table,可以通过搜索require字段并进行排序查找内存占用较大的配置表,并对它进行针对性优化。

关于配置表的优化方案可以阅读《Lua配置表存储优化方案》。

[Lua]字段,按照Lua内存的self进行排序,可以定位GC比较严重的Lua函数,进行针对性优化。也可以查看调用次数等。

在搜索框中搜索[Lua]

善用搜索功能,会揪出很多意想不到的性能问题,比如:老生常谈的Vertex3。

二、监控注册表
以SLua框架的示例Circle.cs 为例:

//Circle.cs
public class Circle : MonoBehaviour {LuaSvr svr;LuaSvr s2;LuaTable self;LuaFunction update;[CustomLuaClass]public delegate void UpdateDelegate(object self);UpdateDelegate ud;void Start () {svr = new LuaSvr();svr.init(null, () =>{self = (LuaTable)svr.start("circle/circle");update = (LuaFunction)self["update"];ud = update.cast<UpdateDelegate>();});......
//Circle.lua
local class={}
function main()local slider = GameObject.Find("Canvas/Slider"):GetComponent(UI.Slider)local counttxt = GameObject.Find("Canvas/Count"):GetComponent(UI.Text)slider.onValueChanged:AddListener(function(v)class:init(v)counttxt.text=string.format("cube:%d",v)end)class.root = GameObject("root")class.ftext = GameObject.Find("Canvas/Text"):GetComponent(UI.Text)class.r=10class.cubes={}class.t=0class.f=0class.framet=0class.max=0class:init()return class
end
function class:update() -- gc alloc is zero0......

C# 层创建的变量self、svr、update等,引用了Lua层的class、update等。

使用该工具得到的引用关系如图所示:

其中“@circle/circle&line:15"的函数为:

function(v)class:init(v)counttxt.text=string.format("cube:%d",v)
end

被添加到UI组件Slider的事件监听中。

“@circle/circle&line:65"的函数为:function class:update(),被一个LuaFunction类型对象update引用。

其中具有key为:bgCurrent、init、root、t等值的table,为Lua代码中的:

local class={}

(其余被引用的table和function是框架初始化时产生的)

C#层是一个ref,内存占用较小,但是Lua层会是一个较为复杂的table或者函数调用等,内存占用较大。当不再使用的C#对象没有被完全释放时,由于C#层内存占用较小,并不会及时进行GC,使得Lua层仍然存在引用,无法进行GC,导致大量内存滞留。

三、Destroy null values统计
在任意一种Lua插件中,都存在类似的机制:在C#层维护一个Cache来引用那些被Lua访问过的C#层对象,防止出现以下的问题:当Lua中再次访问该C#对象时,该对象可能已经被C#层的GC回收掉了,从而导致逻辑错误。所以,在Lua中始终保留某个C#层对象的引用,将会导致其无法被释放,当这样的引用越来越多,就会导致C#层的内存泄漏。

其中比较常见的例子便是:应该被申明为local的对象忘记写local。

function main()cube = GameObject.CreatePrimitive(PrimitiveType.Cube)......

然后切换场景,是用工具检测得到被引用对象为:Cube,如图:

具体引用链为:

当切换场景时,虽然场景中没有了Cube对象,但对象池中还有,导致仍然有引用而无法GC。此时Cube对象是一个作为UnityEngine.Object为空,而作为System.Object不为空的对象,原因就是Lua对其的引用不为空,会导致泄漏。解决方案也较为简单,将Cube变量申明为local局部变量,解除引用即可:

function main()local cube = GameObject.CreatePrimitive(PrimitiveType.Cube)......

更多实战例子可以阅读:https://zhuanlan.zhihu.com/p/89912209

四、Diff两个不同时期的Lua变量
对两个时期的Lua State做两次完整的快照,通过比较两次快照的数据,可以得到相关增加与减少的变量。得到疑似泄露的地方。通过快照获取到的引用链定位泄漏的变量。

该工具得到引用链中:_G表示全局表,_R表示被C#引用的对象

引用链

想要更加深入了解该工具、深入了解Lua性能优化方案的读者,推荐阅读:

1、作者书写的工具介绍与性能检测思路的文章,其中详细解释了Lua、Mono双GC系统、以及Mono对象、Lua对象、Unity对象三者的释放流程以及Lua、C#、C++整个调用流程结构:https://www.zhihu.com/question/307064711

2、UWA Blog中对于Lua性能优化的文章:
《Lua性能优化—Lua内存优化》
《Lua的CPU开销性能优化》

快用UWA Lab合辑Mark好项目!

今天的推荐就到这儿啦,或者它可直接使用,或者它需要您的润色,或者它启发了您的思路......

请不要吝啬您的点赞和转发,让我们知道我们在做对的事。当然如果您可以留言给出宝贵的意见,我们会越做越好。


【博物纳新】是UWA旨在为开发者推荐新颖、易用、有趣的开源项目,帮助大家在项目研发之余发现世界上的热门项目、前沿技术或者令人惊叹的视觉效果,并探索将其应用到自己项目的可行性。很多时候,我们并不知道自己想要什么,直到某一天我们遇到了它。

更多精彩内容请关注:lab.uwa4d.com

Lua Profiler——快速定位Lua性能问题相关推荐

  1. 三步法助你快速定位网站性能问题

    本文分享自华为云社区<在瀑布下用火焰烤饼:三步法助你快速定位网站性能问题>,原文作者:Kagol . 引言 性能,是一个问题. 每个项目成长到一定的规模,都几乎必然要遇到性能问题,当遇到性 ...

  2. sql server datetime取年月_快速定位数据库性能问题,RDS推出慢SQL统计分析

    在使用云的过程中,哪些指标最重要,是安全.弹性,还是计算能力? 其实这些都很关键.除此之外,云最重要的就是数据库了.数据库的性能直接关系到系统执行的效率和稳定性,更与业务紧密相关.如果数据库出现性能问 ...

  3. 在瀑布下用火焰烤饼:三步法助你快速定位网站性能问题(超详细)

    DevUI是一支兼具设计视角和工程视角的团队,服务于华为云 DevCloud平台和华为内部数个中后台系统,服务于设计师和前端工程师. 官方网站: devui.design Ng组件库: ng-devu ...

  4. Lua脚本快速上手(附示例程序代码)

    文章目录 Lua脚本快速入门 前提 基础 注释 保留关键字 变量 变量未声明.未初始化时的类型 局部变量 全局变量 全局变量保存在哪? 全局变量不删除有哪些影响? 全局变量如何删除? 多个变量初始化 ...

  5. Lua+OpenResty快速入门

    Lua+OpenResty快速入门 Lua 概念 特性 应用场景 Lua的安装 Lua的语法 第一个Lua程序 Lua的注释 标识符 关键字 运算符 全局变量&局部变量 Lua数据类型 nil ...

  6. slua 是c语言开发的吗,初学者必备文档:LUA新手快速学习笔记

    LUA程序设计语言 是一个简洁.轻量.可扩展的脚本语言.LUA读作/'lua/(噜啊),是葡萄牙语中"Luna"(月亮)的意思. LUA的目标是成为一个很容易嵌入其它语言中使用的语 ...

  7. Lua Profiler 工具(基于PepperfishProfiler 修改)

    注:本文例子使用的是luajit2.0.5版本,原生lua版本可能有差异,但差异不大. 写在前面: lua性能分析PepperfishProfiler挺好用的,主要灵活,分析的数据也清晰,有嵌套调用的 ...

  8. 90%的人会遇到性能问题,如何用1行代码快速定位?

    阿里妹导读:在<如何回答性能优化的问题,才能打动阿里面试官?>中,主要是介绍了应用常见性能瓶颈点的分布,及如何初判若干指标是否出现了异常. 今天,齐光将会基于之前列举的众多指标,给出一些常 ...

  9. 高性能web平台【Lua语言快速入门】

    Lua快速入门 一.Lua概述 1.1 Lua是什么 Lua 是一个小巧精妙的脚本语言,诞生于巴西的大学实验室,这个名字在葡萄牙语里的含义是"美丽的月亮".Lua开发小组的目标是开 ...

最新文章

  1. 5.7-基于Binlog+Position的复制搭建
  2. [置顶] 2014年八大最热门IT技能
  3. sdut2772 KMP的简单应用
  4. Angular应用双向绑定的语法糖
  5. 远程办公的一天:魔幻24小时
  6. 【linux 开发】定时器使用setitimer
  7. Spring Bean装配(上)
  8. jquerymobile 基础教程
  9. Centos操作系统
  10. 【网络通信 -- SIP 电话】项目实战记录 -- FreeSwitch 服务器搭建与典型 SIP 电话应用
  11. 【GlobalMapper精品教程】011:添加China 2000大地坐标系的方法
  12. 区块链专家洪蜀宁:实现全民普惠的专业化产品设计 | 11月24日【区块链技术与实践】论坛...
  13. 云计算时代,NGINX将是你的“必杀技”
  14. Ansible之管理windows主机
  15. java基础第十五篇之IO流和递归算法
  16. 技术负责人 vs产品负责人_产品前的人
  17. 区块链全球社区协作工具,就用超级表格!
  18. java检索电脑的所有图片_查找电脑里重复的照片
  19. 海南大学计算机学硕直博,24所不歧视本科出身的大学,没有“骚操作”,良心啊...
  20. 导数的定义、性质与求导

热门文章

  1. 字符串循环左|右移实现(C|C++)
  2. GF(2)上任意阶本原多项式的生成—线性反馈移位寄存器
  3. 【打印机】局域网连接打印机
  4. 速卖通代运营可靠吗?如何正确选择代运营?
  5. TIB_js-studiocomm_6.16.0_windows_x86_64下载
  6. 反渗透设备:反渗透水处理设备特点介绍
  7. 【JAVA】贪吃蛇的初步实现(五)
  8. 【运筹优化】结合天际线启发式的蚁群算法求解二维矩形装箱问题 + Java代码实现
  9. SATA 3.0、M.2和PCIe接口,NVMe协议
  10. 岗位竞聘报告PPT模板