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 ...
随机推荐
- mysql创建表时,设置timestamp DEFAULT NULL报错1067 - Invalid default value for 'updated_at'
问题背景: 线上的linux服务器上的mysql服务器中导出数据库的结构.想要在本地创建一个测试版本 导出后再本地mysql上运行却报错 1067 - Invalid default value ...
- Linux系列教程(三)——Linux学习技巧
前面我们讲了Linux系统的详细安装教程,大家跟着教程一步一步的操作,应该能完美的完成安装.那么这篇博客跟大家聊聊如何来学习Linux. 1.工欲善其事必先利其器 ①.第一个问题:通过前面在虚拟软件中 ...
- Linux进程间通信(System V) --- 消息队列
消息队列 IPC 原理 消息队列是消息的链式队列,如下图为消息队列的模型.整个消息队列有两种类型的数据结构. 1.msqid_ds 消息队列数据结构:描述整个消息队列的属性,主要包括整个消息队列的权限 ...
- VB.NET网络是否联通Function
''' <summary> ''' IP Ping ''' </summary> ''' <param name="strIpOrDName& ...
- LeetCode算法笔记目录
贪心算法: LeetCode翻转矩阵后的得分-Python3<六> LeetCode根据身高重建队列-Python3<七> LeetCode 任务调度器-Python3< ...
- 【转】Dubbo和JDK的SPI究竟有何区别?
前言 上一篇简单的介绍了spi的基本一些概念,但是其实Dubbo对jdk的spi进行了一些改进,具体改进了什么,来看看文档的描述 JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩展实现初 ...
- 通过kubernetes构建ela服务
一.kubernetes 通过yaml 创建pod与service apiVersion: extensions/v1beta1 kind: Deployment metadata: name: el ...
- 4个错误使用JavaScript数组方法的案例
译者按: 做一个有追求的工程师,代码不是随便写的! 原文: Here's how you can make better use of JavaScript arrays 译者: Fundebug 为 ...
- 使用svn钩子遇到的坑
1.svn钩子(hooks)自动部署代码到web目录(以前公司用,很好奇怎么做的,折腾了两天,掉进了坑里)共勉!!! web目录:/home/www/xiaokai svn版本库目录:/svn/xia ...
- 自定义jq插件,鼠标悬浮展示图片或者视频放大图,可自定义展示内容
网站项目经常会遇到一些视频或者图片素材的展示功能,那么就需要自己写一个功能,就是在一些列表页面你想要是这个数据的详细内容,弹框在页面某个位置 例如这是视频悬浮展示效果,可自定义自动播放等属性标签 又例 ...