当前位置: 首页 > news >正文

lua(xlua)基础知识点记录二

1. 关于lua函数传参参数

在lua中给function传递参数的时候一般分为两种情况:值传递和引用传递

值传递:

值传递:数字、字符串、布尔值、nil等基本类型通过值传递。函数内部接收的是外部变量的副本,修改副本不会影响原始变量。
虽然我们都知道字符串是引用类型存储的数据,但是在函数传参的时候传递的是指向字符串内存地址的指针值​(即引用的副本),而非原始变量的引用本身

function Test(n)n = n + 1
end
local a = 1
Test(a)
print("输出a:"..a)
-- 结果a仍然是1

引用传递:

​表(table)和函数如果当作函数的参数传递时,传递的时指向具体变量的地址的副本,记住时副本!!可以理解成表本身就是一个指针,把这个指针当作参数传递给函数时,会重新生成一个指针,并且把该变量的指针地址值复制给新生成的指针。所以这种情况下,如果直接操作(增删)都可以正常影响指向的变量数据。但是如果时赋值操作,那么就会修改传递过去的副本指向的内容。

function Test1(t)t.a = 1
endfunction Test2(t)t = {a = 15,b =3}
endfunction Test3(t)t = nil
endlocal t = {a = 10, b = 2}Test1(t)
print("t.a:"..t.a.." t.b:"..t.b)
Test2(t)
print("t.a:"..t.a.." t.b:"..t.b)
Test3(t)
print("t.a:"..t.a.." t.b:"..t.b)

上述代码三次的输出都是: t.a:1 t.b:2,
.
调用Test1的时候直接修改了引用指向的内容,所以修改生效。此时外部的t.a = 1。
.
调用Test2的时候直接把引用副本指向了另一个新表的内存,那么这时候函数内部的t已经和外部传进去的t没有关系了,所以怎么修改都不会对外部的t造成影响。
.
调用Test3的时候和Test2一样,把引用副本指向了空,同样和外部的t没有关联关系了,所以外部t不受影响。

2. 关于c#和lua相互引用(xlua版)

userdata

我们都知道lua中有一种数据类型-userdata
.
userdata 是 Lua 为存储 C/C++ 等外部语言数据而设计的特殊类型,提供了一块原始内存区域,可直接存放结构体、指针、文件句柄等外部对象。它允许 Lua 通过指针或内存块直接操作外部环境的数据,是 Lua 与 C/C++ 交互的核心机制。例如,C 中定义的 struct People 可通过 userdata 传递给 Lua 脚本使用.
.
所以一个语言只要可以和c/c++交互,那么就可以通过userdata和lua交互,这也是c#和lua交互的底层原理。
.

xlua中的c#和lua交互

在xlua中,c#和lua的交互都是通过c这个他们两种语言都能到的媒介实现的。
大致流程如下:

lua call c#

lua调用c# -> 调用c -> 操作虚拟栈对参数压栈 -> 调用c#wrap函数/反射查找函数 ->
把lua函数参数转换成c#类型 -> 完成调用

c# call lua

c#调用lua -> c#调用c函数 -> 通过capi找到lua函数(lua_getglobal) -> c#数据转成lua数据(lua_pushinteger) ->
通过capi调用lua函数(lua_pcall)

xlua中c#和lua相互引用

在xlua框架中,可以很方便的在lua中持有C#的对象变量并使用,反之一样。

lua持有c#对象:

通过上述的userdata了解,我们可以大致了解到,其实c#的变量在lua中是以userdata类型的数据存储的。
事实上在lua中从来没有真正的持有c#的真正变量。

​C#对象在Lua中的表示

在xLua中,C#对象传递到Lua时会被封装为userdata类型。这个userdata并不直接存储C#对象本身,而是存储一个唯一标识符(objId)​,用于关联C#端的实际对象

引用关系的管理(lua持有#)

但是我们也知道c#的gc是并不清楚lua环境中该userdata的引用情况的,如果直接不管lua中是否引用只要c#段就没有引用就GC掉显然不符合我们的需求。所以xlua中设计了ObjectTranslator.cs。
ObjectTranslator通过ObjectPool和ReverseMap维护对象与objId的映射,确保C#对象不被GC回收(只要Lua仍持有userdata)
而在lua中,userdata是被存放在弱引用表中的,只要lua中没有强引用该对象的存在,那么该userdata就可以被lua的gc回收掉,防止lua一致持有着objid而c#无法回收对应对象。

lua对象在c#中的表示:

所有Lua对象在C#中通过LuaBase基类管理,其构造函数调用luaL_ref在Lua注册表中创建引用,析构时调用luaL_unref释放

其实讲了那么多,就是为了理解如下代码:

public class Main{public class TestClass{}public static TestClass MyClassTest;public static TestClass CreateTestClass(){if (MyClassTest == null) MyClassTest = new TestClass();return MyClassTest;}public static void DestroyTestClass(){MyClassTest = null;}
}
local myClass,myClass2,myClass3local function Execute()myClass = CS.Main.CreateTestClass()myClass2 = CS.Main.MyClassTestmyClass3 = myClass2myClass2 = nilcollectgarbage("collect")CS.System.GC.Collect()CS.Main.DestroyTestClass()collectgarbage("collect")CS.System.GC.Collect()
endpcall(Execute)

由上面讲述我们可以知道,一个c#变量在lua中的话,两端是各自持有各自的类型(userdata和TestClass),上述lua代码中的myClass,myClass2和myClass3就是对应的userdata。
.
即使myClass2 = nil后,myClass3和myClass仍然持有该userdata,所以第一次执行双方gc,只会回收掉myClass2。myClass3和myClass以及c#段的MyClassTest都没收影响。
.
那么再来看CS.Main.DestroyMyClass() 这句之后c#侧的MyClassTest引用被置空,注意只是引用实际变量还被lua持有,所以即使执行了C#的gc,真正的对象仍不会被回收掉,因为myClass 和myClass3仍然还存在着并且持有着。
.
那么这时候如何回收掉TestClass对应的数据,只需要再加上
myClass2 = nil
myClass = nil
collectgarbage("collect")
CS.System.GC.Collect()
这样的话lua测得强引用也没了,都可以被回收了

http://www.lryc.cn/news/591042.html

相关文章:

  • STM32上移植Lua解析器
  • Android15系统实现刷机防呆功能
  • 【JVM】深入理解 JVM 类加载器
  • MySQL如何解决事务并发的幻读问题
  • JVM 内存分配与垃圾回收策略
  • macOS 字体管理全攻略:如何查看已安装字体及常见字体格式区
  • 网络编程7.17
  • JAVA中的Collection集合及ArrayList,LinkedLIst,HashSet,TreeSet和其它实现类的常用方法
  • MyBatis延迟加载(Lazy Loading)之“关联查询”深度解析与实践
  • 【44】MFC入门到精通——MFC 通过Button按钮添加控件变量实现:按下 按钮变色 (比如开关 打开关闭状态) MFC更改button控颜色
  • 数据结构-2(链表)
  • 基于STM32闭环步进电机控制系统设计说明
  • Leaflet地图交互:实现图形与点的同时高亮效果
  • PyTorch生成式人工智能(18)——循环神经网络详解与实现
  • 【Linux基础知识系列】第五十一篇 - Linux文件命名规范与格式
  • Mac 安装及使用sdkman指南
  • Java 大视界 -- Java 大数据在智能交通智能公交站台乘客流量预测与服务优化中的应用(349)
  • Flask+LayUI开发手记(十一):选项集合的数据库扩展类
  • Java 集合框架详解:Collection 接口全解析,从基础到实战
  • 【LeetCode 热题 100】108. 将有序数组转换为二叉搜索树
  • 【Redis 】看门狗:分布式锁的自动续期
  • 如何用Kaggle免费GPU
  • [yotroy.cool] Git 历史迁移笔记:将 Git 项目嵌入另一个仓库子目录中(保留提交记录)
  • 语雀编辑器内双击回车插入当前时间js脚本
  • 【WRFDA第六期】WRFDA 输出文件详述
  • R语言基础| 基本图形绘制(条形图、堆积图、分组图、填充条形图、均值条形图)
  • Spring AI之Prompt开发
  • Web攻防-PHP反序列化Phar文件类CLI框架类PHPGGC生成器TPYiiLaravel
  • Cursor开发步骤
  • 【C++指南】C++ list容器完全解读(四):反向迭代器的巧妙实现