【Unity/XLua】xlua自带教程示例分析(五)—— 优化GC

[复制链接]
发表于 2026-2-10 16:58:40 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
在Xlua中,利用[GCOptimize]可以制止C#和Lua间通报值范例(平凡值范例,只包罗值范例的strcut或嵌套struct,罗列范例,以及它们构成的数组)时发生gc alloc
lua脚本

  1. function id(...)
  2.     return ...
  3. end
  4. function add(a, b) return a + b end
  5. function array_exchange(arr)
  6.     arr[0], arr[1] = arr[1], arr[0]
  7. end
  8. local v3 = CS.UnityEngine.Vector3(7, 8, 9)
  9. local vt = CS.XLuaTest.MyStruct(5, 6)
  10. function lua_access_csharp()
  11.     monoBehaviour:FloatParamMethod(123) --primitive
  12.     monoBehaviour:Vector3ParamMethod(v3) --vector3
  13.     local rnd = math.random(1, 100)
  14.     local r = monoBehaviour:Vector3ParamMethod({x = 1, y = 2, z = rnd}) --vector3
  15.     assert(r.x == 1 and r.y == 2 and r.z == rnd)
  16.     monoBehaviour:StructParamMethod(vt) --custom struct
  17.     r = monoBehaviour:StructParamMethod({a = 1, b = rnd, e = {c = rnd}})
  18.     assert(r.b == rnd and r.e.c == rnd)
  19.     monoBehaviour:EnumParamMethod(CS.XLuaTest.MyEnum.E2) --enum
  20.     monoBehaviour:DecimalParamMethod(monoBehaviour.a5[0])
  21.     monoBehaviour.a1[0], monoBehaviour.a1[1] = monoBehaviour.a1[1], monoBehaviour.a1[0] -- field
  22. end
  23. exchanger = {
  24.     exchange = function(self, arr)
  25.         array_exchange(arr)
  26.     end
  27. }
  28. A = { B = { C = 789}}
  29. GDATA = 1234;
复制代码
表明
这段代码是Lua脚本的示例,团结了与C#交互的一些功能。让我们逐个表明:

  • 函数 id(...) 和 add(a, b):

    • id(...) 函数是一个不定参数的函数,它返回吸取到的全部参数。
    • add(a, b) 函数简朴地盘算两个参数的和并返回效果。该
    这两个函数的目的是要测试让数据从C#传入lua再传回C#,观察gc情况


  • 函数 array_exchange(arr):

    • 这个函数交换了数组 arr 的第一个和第二个元素的位置。Lua中的数组索引从1开始,因此 arr[0] 实际上是 arr[1],arr[1] 是 arr[2]。
    该函数利用了lua的等号特性,本质是一个swap函数,而且只交换arr的头两个数据


  • 界说了两个变量 v3 和 vt:

    • v3 是一个利用C#的Unity引擎的 Vector3 布局体,体现一个三维向量 (7, 8, 9)。
    • vt 是一个自界说的布局体 MyStruct 的实例,此中包罗字段 (5, 6)。


  • 函数 lua_access_csharp():

    • 这个函数演示了如安在Lua中访问和调用C#中的方法和字段:

      • monoBehaviour:FloatParamMethod(123) 调用了一个担当单精度浮点数参数的方法。
      • monoBehaviour:Vector3ParamMethod(v3) 通报了一个 Vector3 范例的参数给一个担当 Vector3 的方法。
      • 利用 math.random(1, 100) 天生一个随机数 rnd,然后通报给一个担当 Vector3 参数的方法,并验证返回的效果。
      • monoBehaviour:StructParamMethod(vt) 通报了一个自界说布局体范例的参数。
      • 类似地,通报一个包罗字段的表给一个担当布局体参数的方法,并验证返回效果。
      • monoBehaviour:EnumParamMethod(CS.XLuaTest.MyEnum.E2) 通报了一个罗列范例的参数。
      • monoBehaviourecimalParamMethod(monoBehaviour.a5[0]) 通报了一个十进制数参数。
      • 末了一行交换了一个数组 monoBehaviour.a1 的两个元素的位置。

    monoBehaviour是在C#中set的变量,即this,以是这里是在利用C#函数处置惩罚lua对象


  • 变量 exchanger:

    • exchanger 是一个包罗 exchange 方法的表,该方法担当一个数组参数并调用 array_exchange 函数来交换数组的两个元素。
    该表在C#中创建有对应函数的接口获取,通过C#的接口调用其方法


  • 全局变量 A 和 GDATA:

    • A 是一个嵌套表布局,此中包罗 B 字段,B 字段包罗 C 字段。
    • GDATA 是一个全局变量,存储整数值 1234。

​ 这两个变量会在C#中每次取出,而且 + 1放回

C#调用过程

  1. [GCOptimize]
  2. [LuaCallCSharp]
  3. public struct Pedding
  4. {
  5.     public byte c;
  6. }
  7. [GCOptimize]
  8. [LuaCallCSharp]
  9. public struct MyStruct
  10. {
  11.     public int a;
  12.     public int b;
  13.     public decimal c;
  14.     public Pedding e;
  15. }
  16. [LuaCallCSharp]
  17. public enum MyEnum
  18. {
  19.     E1,
  20.     E2
  21. }
复制代码
利用GCOptimize优化只有值范例的Struct以及嵌套Struct
利用LuaCallCSharp指示Lua可以调用这些Struct

  1. [CSharpCallLua]
  2. public delegate int IntParam(int p);
  3. [CSharpCallLua]
  4. public delegate Vector3 Vector3Param(Vector3 p);
  5. [CSharpCallLua]
  6. public delegate MyStruct CustomValueTypeParam(MyStruct p);
  7. [CSharpCallLua]
  8. public delegate MyEnum EnumParam(MyEnum p);
  9. [CSharpCallLua]
  10. public delegate decimal DecimalParam(decimal p);
  11. [CSharpCallLua]
  12. public delegate void ArrayAccess(Array arr);
  13. [CSharpCallLua]
  14. public interface IExchanger
  15. {
  16.     void exchange(Array arr);
  17. }
复制代码
创建一系列delegate吸取Lua函数,以及一个接口吸取lua的表



以上都是类外的前期声明准备,接下来是在类中的字段界说
起首最告急的一点是,类要加上LuaCallCSharp的标签,由于反面会在内里向Lua传入自己的this指针,因此lua是可以调用类的
在类中,先界说一些等会要用到的妙妙工具(字段)
  1. IntParam f1;
  2. Vector3Param f2;
  3. CustomValueTypeParam f3;
  4. EnumParam f4;
  5. DecimalParam f5;
  6. ArrayAccess farr;
  7. Action flua;
  8. IExchanger ie;
  9. LuaFunction add;
  10. [NonSerialized]
  11. public double[] a1 = new double[] { 1, 2 };
  12. [NonSerialized]
  13. public Vector3[] a2 = new Vector3[] { new Vector3(1, 2, 3), new Vector3(4, 5, 6) };
  14. [NonSerialized]
  15. public MyStruct[] a3 = new MyStruct[] { new MyStruct(1, 2), new MyStruct(3, 4) };
  16. [NonSerialized]
  17. public MyEnum[] a4 = new MyEnum[] { MyEnum.E1, MyEnum.E2 };
  18. [NonSerialized]
  19. public decimal[] a5 = new decimal[] { 1.00001M, 2.00002M };
复制代码
前五个委托吸取Lua的id函数,差别的值范例数据都测了一遍(从C#传lua再传返来)
farr吸取lua的交换函数,传入数组,交换数组头两个元素,再传返来
flua吸取lua_access_csharp()函数,负责触发lua去访问c#的变量和函数
ie传入表exchanger,并通过内里的函数去访问交换函数(同2)
add是用LuaFunction对象创建的,可以通过add.Func<int, int, int>(34, 56); // LuaFunction.Func<T1, T2, TResult> 的方式访问。
反面的a1 ~ a5则是为交换函数准备的差别范例的数组

  1. luaenv.DoString(script);
  2. luaenv.Global.Set("monoBehaviour", this);
  3. luaenv.Global.Get("id", out f1);
  4. luaenv.Global.Get("id", out f2);
  5. luaenv.Global.Get("id", out f3);
  6. luaenv.Global.Get("id", out f4);
  7. luaenv.Global.Get("id", out f5);
  8. luaenv.Global.Get("array_exchange", out farr);
  9. luaenv.Global.Get("lua_access_csharp", out flua);
  10. luaenv.Global.Get("exchanger", out ie);
  11. luaenv.Global.Get("add", out add);
  12. luaenv.Global.Set("g_int", 123);
  13. luaenv.Global.Set(123, 456);
  14. int i;
  15. luaenv.Global.Get("g_int", out i);
  16. Debug.Log("g_int:" + i);
  17. luaenv.Global.Get(123, out i);
  18. Debug.Log("123:" + i);
复制代码
接下来先在luaenv中运行脚本,再将对应的值提取到C#字段中,详细对应关系上一段已经说了

  1. // c# call lua function with value type but no gc (using delegate)
  2. //仅仅传递数值再返回C#中
  3. f1(1); // primitive type
  4. f2(new Vector3(1, 2, 3)); // vector3
  5. MyStruct mystruct1 = new MyStruct(5, 6);
  6. f3(mystruct1); // custom complex value type
  7. f4(MyEnum.E1); //enum
  8. decimal dec1 = -32132143143100109.00010001010M;
  9. f5(dec1); //decimal
  10. // using LuaFunction.Func<T1, T2, TResult>
  11. //使用LuaFunction风格的函数触发
  12. add.Func<int, int, int>(34, 56); // LuaFunction.Func<T1, T2, TResult>
  13. // lua access c# value type array no gc
  14. //传递数组进去并交换头两个数的位置再传回来
  15. farr(a1); //primitive value type array
  16. farr(a2); //vector3 array
  17. farr(a3); //custom struct array
  18. farr(a4); //enum arry
  19. farr(a5); //decimal arry
  20. // lua call c# no gc with value type
  21. //让lua侧调用C#变量
  22. flua();
  23. //c# call lua using interface
  24. //使用接口风格调用表中的交换数组头两个元素的函数
  25. ie.exchange(a2);
  26. //no gc LuaTable use
  27. //直接设置获取lua中的值的数
  28. luaenv.Global.Set("g_int", 456);
  29. int i;
  30. luaenv.Global.Get("g_int", out i);
  31. luaenv.Global.Set(123.0001, mystruct1);
  32. MyStruct mystruct2;
  33. luaenv.Global.Get(123.0001, out mystruct2);
  34. decimal dec2 = 0.0000001M;
  35. luaenv.Global.Set((byte)12, dec1);
  36. luaenv.Global.Get((byte)12, out dec2);
  37. //这两个是lua中定义的值和嵌套表,访问和修改其也不会产生gc
  38. int gdata = luaenv.Global.Get<int>("GDATA");
  39. luaenv.Global.SetInPath("GDATA", gdata + 1);
  40. int abc = luaenv.Global.GetInPath<int>("A.B.C");
  41. luaenv.Global.SetInPath("A.B.C", abc + 1);
  42. //lua手动gc函数
  43. luaenv.Tick();
复制代码
这一段代码是Update中的,会每帧实行,重要是展示大量通报数据下不会产生gc alloc

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表