Unity Ulua1.03优化记录
现在项目的框架是在2015年设计的,那时候Ulua还处于1.03版本,现在回头再看,Ulua已经迭代到1.25版本,中间引入带有wraper的cstolua,而后转向现有的toLua#版本。
随着版本更新性能提升了很多(当然也看人为因素),代码的清晰度也越来越清晰,但是引入的项目本身可能不需要的东西越来越多,比如Gameobject、vector等等,这些并不在我们现有框架需求的范围内。所以在这次优化过程中并没有直接拿最新的toLua#来替换现在的Lua交互模块,而是将后续版本中能够改善现有性能的部分逐步添加进来,保证框架本身的稳定性。下文主要介绍cstolua版本优化之后的实现方式以及与当前1.03对比。
C#调用 Lua Function--缓存机制
每个版本中对Lua table的均支持通过"."分割操作。
/*
* Navigates a table in the top of the stack, returning
* the value of the specified field
*/
internal object getObject(string[] remainingPath)
{
object returnValue = null;
for (int i = 0; i < remainingPath.Length; i++)
{
LuaDLL.lua_pushstring(L, remainingPath[i]);
LuaDLL.lua_gettable(L, -2);
returnValue = translator.getObject(L, -1);
if (returnValue == null) break;
}
return returnValue;
}
如果你使用的Lua函数层级比较深,同时还要处理一些堆栈操作和校验,获取效率是没有保证的,当然也可以通过保存需要的LuaFunction避免这个问题。在后续版本中增加了LuaTable和LuaFunction缓冲的功能,对使用多的函数或者table保存下来,避免后续重复的查找。
public LuaFunction GetLuaFunction(string name)
{
LuaBase func = null;
if (!dict.TryGetValue(name, out func))
{
IntPtr L = lua.L;
int oldTop = LuaDLL.lua_gettop(L);
if (PushLuaFunction(L, name))
{
int reference = LuaDLL.luaL_ref(L, LuaIndexes.LUA_REGISTRYINDEX);
func = new LuaFunction(reference, lua);
func.name = name;
dict.Add(name, func);
}
else
{
Debugger.LogError("Lua function {0} not exists", name);
}
LuaDLL.lua_settop(L, oldTop);
}
else
{
func.AddRef();
}
return func as LuaFunction;
}
LuaTable获取采用类似的方案,代码不在贴出。
Lua调用C# Function -- 干掉反射
Lua1.03版本中主要使用反射机制实现Lua对函数的调用,主要流程:
- Lua使用时通过luanet.import_type注册需要的对象类型,在C#层通过反射获得Assembly对象,并记录下来
public static int loadAssembly(IntPtr luaState)
{
ObjectTranslator translator = ObjectTranslator.FromState(luaState);
string assemblyName = LuaDLL.lua_tostring(luaState, 1);
Assembly assembly = null;
assembly = Assembly.Load(assemblyName);
if (assembly != null && !translator.assemblies.Contains(assembly))
{
translator.assemblies.Add(assembly);
}
}
return 0;
}
- 在使用到注册对象的类型时,通过反射获取该方法并执行 ,具体可以查看 MetaFunctions.getMember()函数的实现。
C#的反射机制为什么慢,可考:C#会重蹈覆辙吗?系列之2:反射及元数据的性能问题,慢可以接受,但还有一点是产生一堆临时对象,也就是会有GC存在。如果在框架层次严格的控制Lua和C#的交互时机和接口标准,完全也可以满足游戏需求。但是在多人开发中慢慢的就会走向另外一个方向,接口变多,标准不在。对于在大量在Lua层操作Unity对象的框架,在加上快速开发中的不关注,后期游戏的交互的性能估计更严重。
Ulua的后续版本中就增加了可以避免取消反射机制,即采用Lua全局注册的方式使用C#方法。具体流程:
- 定义需要导出的类
public static BindType[] binds = new BindType[]
{
_GT(typeof(DebugExport)),
}
- 通过自动化工具生成需要的注册文件(wraper file),注册文件中实现每个类方法与Lua堆栈的交互过程;类似与下面:
//注册方法,关键在LuaScriptMgr.RegisterLib
public static void Register(IntPtr L)
{
LuaMethod[] regs = new LuaMethod[]
{
new LuaMethod("RegisterLog", RegisterLog),
new LuaMethod("LogError", LogError),
new LuaMethod("LogWarning", LogWarning),
new LuaMethod("Log", Log),
new LuaMethod("ClearLog", ClearLog),
};
LuaField[] fields = new LuaField[]
{
};
LuaScriptMgr.RegisterLib(L, "DebugExport", regs,1);
}
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
static int LogError(IntPtr L)
{
LuaScriptMgr.CheckArgsCount(L, 1); //检测参数个数
string arg0 = LuaScriptMgr.GetLuaString(L, 1); //获取第一个参数
DebugExport.LogError(arg0); //调用Unity 方法
return 0;
}
- 游戏启动时首先将注册文件中的方法全部注册到Lua全局表中(也就是调用Wraper中Register),这样就后面在Lua中可以直接使用这些方法。
对象 -- 尽量避免开箱和装箱操作
不管是C#调用Lua还是Lua调用C#,不可避免的都会涉及到参数问题。
类型转换 c#中不可绕过的就是对象转换的代价,参考文章:深入理解C#的装箱和拆箱 , OK,频繁的开箱和装箱操作会额外耗费CPU和内存资源,所以在1.03后续版本中引入重载,对不同的数据类型提供不同的接口,同时在函数调用层次也提供一些优化方式来避免,比如讲函数调用开放给编码的人,比如C#层调用Lua层Update函数,带有两个参数,可以这样修改:
void CallUpdate(LuaFunction updateFunc, float deltaTime, float unscaledDeltaTime)
{
int top = updateFunc.BeginPCall();
IntPtr L = updateFunc.GetLuaState();
//带有重载
LuaScriptMgr.Push(L, deltaTime);
//带有重载
LuaScriptMgr.Push(L, unscaledDeltaTime);
updateFunc.PCall(top, 2);
updateFunc.EndPCall(top);
}
当然对于带有返回数据的函数也会存在这样的问题,优化方式类似,提供足够的重载函数来满足需求。当然对于要使用Gameobject、自定义类、委托等等的肯定还是避免不了.
对象生命周期管理方式
tolua#中 对象的生命周期管理和垃圾回收策略做了很大的优化,不过鉴于当前的框架中并没有对象作为参数,所有没有做进一步的修改。
结束语
后续版本中做的优化可能不止这些,但是通过上面的改善以及在逻辑层次注意和规范,应该可以满足现有要求,前提是在现有框架下。得益于现有框架对接口的定义,不存在使用GameObject等Unity内置类型或者委托之类的情况,所以避免了很多比如对象生命周期等问题。
参考:
[1]用好lua+unity,让性能飞起来——lua与c#交互篇 :http://www.cnblogs.com/zwywilliam/p/5999924.html
[2]:ulua中lua代码使用反射调用c#详解 http://blog.csdn.net/wdsdsdsds/article/details/54409936?utm_source=itdadao&utm_medium=referral
Unity Ulua1.03优化记录的更多相关文章
- 浅谈Unity的渲染优化(1): 性能分析和瓶颈判断(上篇)
http://www.taidous.com/article-667-1.html 前言 首先,这个系列文章做个大致的介绍,题目"浅谈Unity",因为公司和国内大部分3D手游开发 ...
- 通过profiler对unity进行针对性优化
转 : http://user.qzone.qq.com/289422269/blog/1453815629?ptlang=2052 通过profiler对unity进行针对性优化 1. CPU U ...
- Unity MMORPG游戏优化经验分享
https://mp.weixin.qq.com/s/thGF2WVUkIQYQDrz5DISxA 今天由Unity技术支持工程师高岩,根据实际的技术支持工作经验积累,分享如何对Unity MMORP ...
- Unity 几种优化建议
转: http://user.qzone.qq.com/289422269/blog/1453815561?ptlang=2052 Unity 几种优化建议 最简单的优化建议: 1.PC平台的话保持场 ...
- VS2010/2012配置优化记录笔记
VS2010/2012配置优化记录笔记 在某些情况下VS2010/2012运行真的实在是太卡了,有什么办法可以提高速度吗?下面介绍几个优化策略,感兴趣的朋友可以参考下,希望可以帮助到你 有的时候V ...
- Unity教程之再谈Unity中的优化技术
这是从 Unity教程之再谈Unity中的优化技术 这篇文章里提取出来的一部分,这篇文章让我学到了挺多可能我应该知道却还没知道的知识,写的挺好的 优化几何体 这一步主要是为了针对性能瓶颈中的”顶点 ...
- Unity 绘图性能优化 - Draw Call Batching
Unity 绘图性能优化 - Draw Call Batching Unity官方链接:http://docs.unity3d.com/Manual/DrawCallBatching.html 转载请 ...
- Unity UI性能优化技巧
本文将介绍一些提升Unity UI性能的技巧.更多优化技巧,可以观看Unity工程师Ian Dundore在Unite Europe 2017的演讲<使用Unity性能提升技巧>. 1.划 ...
- React性能优化记录(不定期更新)
React性能优化记录(不定期更新) 1. 使用PureComponent代替Component 在新建组件的时候需要继承Component会用到以下代码 import React,{Componen ...
随机推荐
- U3D Time类
Time.time 表示从游戏开发到现在的时间,会随着游戏的暂停而停止计算. Time.timeSinceLevelLoad 表示从当前Scene开始到目前为止的时间,也会随着暂停操作而停止. Tim ...
- [HEOI2016] 字符串
Description 给定长度为n的字符串,m次询问,每次询问s[a...b]的所有子串与s[c...d]的LCP的最大值.n,m<=10^5. Solution 感觉这种n,m<=10 ...
- typeof() 和 GetType()区是什么
1.typeof(x)中的x,必须是具体的类名.类型名称等,不可以是变量名称. 2.GetType()方法继承自Object,所以C#中任何对象都具有GetType()方法,它的作用和typeof() ...
- 远程登陆Linux服务器
Xshell 强大的ssh客户端,通过互联网到远程主机.下载:http://www.netsarang.com/download/down_form.html?code=622 1.安装完,新建会话 ...
- python爬虫入门---第一篇:获取某一网页所有超链接
这是一个通过使用requests和BeautifulSoup库,简单爬取网站的所有超链接的小爬虫.有任何问题欢迎留言讨论. import requests from bs4 import Beauti ...
- 【工具相关】ionic-通过nmp安装最新版本的 cordova 和 ionic
一,命令行下输入: sudo npm install -g cordova ionic 用来安装最新版本的cordova和ionic. 如下图所示: 二,等待一下,如下图所示. 三,用命令 npm u ...
- web全栈架构师[笔记] — 02 数据交互
数据交互 一.http协议 基本特点 1.无状态的协议 2.连接过程:发送连接请求.响应接受.发送请求 3.消息分两块:头.体 http和https 二.form 基本属性 action——提交到哪儿 ...
- Java 开源博客 Solo 1.8.0 发布 - 改进文件上传
本次发布主要是更新了编辑器,使其更好地支持文件上传.(1.8.0 版本变更记录请看这里) 我们的 Markdown 编辑器: 另外,我们对 HTTPS 的支持也更完善了,欢迎大家试用! 简介 Solo ...
- cve-list
dlink CVE-2018-17786 CVE-2018-17787 CVE-2018-17880 CVE-2018-17881 mongoose CVE-2018-10945 openwrt CV ...
- 微信小程序-06-详解介绍.js 逻辑层文件-注册页面
上一篇介绍的是 app.js 逻辑层文件中注册程序,对应的每个分页面都会有的 js 文件中 page() 函数注册页面 微信小程序-06-详解介绍.js 逻辑层文件-注册页面 宝典官方文档: http ...