跳到主要内容

0GC Marshal

本篇只谈 少分配 / 零额外托管分配 的常用 Marshal 手段。默认规则见 速查表;特性语法见 LuaMarshalAs。权威:04-OPAQUE02-MARSHAL-AS

「0GC」指热路径上 尽量不 为这次互调新建 Lua table / Lua string / ByVal userdata / 装箱对象。并非整个程序永不 GC。

1. OpaqueValue:引用类型与 struct

OpaqueValue 是 lightuserdata 句柄(无 metatable),Push 时不建 ByObj/ByVal userdata。

场景行为
ref / out / in T(任意 T)C#→Lua 默认 Opaque,无需标注
by-val 任意 CLR 类型可显式 [LuaMarshalAs(OpaqueValue)]仅 C#→Lua
public void Touch(ref Transform t) { } // 默认 Opaque
public void Peek([LuaMarshalAs(LuaMarshalType.OpaqueValue)] MyClass obj) { }
public void PeekStruct([LuaMarshalAs(LuaMarshalType.OpaqueValue)] Vector3 v) { }
-- 在同一次 C#→Lua 同步调用链内
local v = zlua.get_opaquevalue(slot)
zlua.set_opaquevalue(slot, newValue)
-- 需要 userdata 门面时:zlua.to_user_data(slot)(会产生 userdata,见规范)

要点:

  • 引用类型struct 都可走 Opaque,避免为本帧临时对象建完整 userdata
  • 不可把 Opaque 存进跨 pcall / 跨帧的全局表
  • Lua→C# 单独形参上标 OpaqueValue 非法;写回规则见 ref/out/in

2. UnpackedValues:struct 多槽展开

普通 struct / 闭合泛型 struct,用多连续栈槽 ↔ Members创建 Lua table,也 创建 ByVal userdata:

public void ApplyForce(
[LuaMarshalAs(LuaMarshalType.UnpackedValues, Members = new[] { "x", "y", "z" })]
Vector3 force) { }
rb:ApplyForce(0, 9.8, 0) -- 三槽;Lua 侧只有 number
适用不适用
struct / closed generic structNullable<T>(规范禁止;无法用多槽表达「无值」)
热路径 Vector2 / Vector3 / 自定义 blittable 小结构class / interface

Nullable<struct> 需要「可空」语义时用 Tablenil↔无值),但 table 本身有 Lua 分配,不算本节意义下的 0GC;C#→Lua 临时可空值也可考虑 Opaque

返回值同样可展开为多返回值:

[return: LuaMarshalAs(LuaMarshalType.UnpackedValues, Members = new[] { "X", "Y" })]
public Vec2 GetDelta() => ...;
local dx, dy = host:GetDelta()

3. UserData:巨大 string 走 ByObj

默认:string ↔ Lua string(按内容拷贝)。对超大文本 / 二进制当文本的缓冲,拷贝成本高:

public void ProcessHuge(
[LuaMarshalAs(LuaMarshalType.UserData)] string payload) { }

标注后强制 ByObjUserData(托管 System.String 对象),不再生成对应内容的 Lua string。

:::warning 并不少见地「更省」 ByObjUserData 仍会在 Lua 侧分配 userdata,参与 Lua GC。只是避免「再复制一整份 Lua string」。日常短字符串继续用默认即可;本用法 不常见。 :::

byte[] 若要 octet 语义,用 Bytes(↔ Lua string),与本节目标不同。

对照速记

手段典型目标Lua 侧额外分配
OpaqueValueC#→Lua 的 class / struct / byref无 userdata/table(仅 lightuserdata 句柄)
UnpackedValuesLua↔C# 的 struct 字段展开无(只用栈上 number 等)
Tablestruct / Nullable<struct> 键值 table
UserData on string巨大 string 避免 Lua string 拷贝 ByObj userdata

学习路径

上一篇LuaMarshalAs
下一篇方法重载

相关文档