原生代码生成

*此内容使用人工智能(Beta)翻译,可能包含错误。若要查看英文页面,请点按 此处。

通过 Luau 对原生代码生成的支持,您游戏中的脚本¹ 可以直接编译成 CPU 执行的机器代码指令,而不是 Luau 虚拟机操作的常规字节码。此功能可以提高某些支持脚本的执行速度,特别是那些进行大量数值计算且很少调用重型 Luau 库或 Roblox API 的脚本。

1 原生代码生成仅支持服务器端脚本和 Android 设备上的客户端脚本。未来可能会支持更多设备。

启用原生代码生成

要为 Script 启用原生代码生成,请在顶部添加 --!native 注释:²

--!native
print("Hello from native code!")

这将为脚本中的所有函数启用原生代码生成,并在被认为有利的情况下启用顶层作用域。无需其他更改;原生执行脚本的行为与之前完全相同,只有性能不同。Luau 语言的所有功能和所有 Roblox API 仍然受支持。

或者,您可以通过添加 @native 属性为单个函数启用原生代码生成:

@native
local function f(x)
return (x + 1)
end
2 在未来,如果确定某些脚本运行原生是有利的,它们可能会自动开始以原生方式运行,但目前仍需要手动放置 --!native 注释。

最佳实践

以下提示将帮助您最大限度地受益于原生代码生成:

  • 最好在直接在 Luau 中执行大量计算的脚本中启用此功能。如果您在表上进行大量数学运算,尤其是 buffer 类型,则该脚本可能是一个不错的候选者。

  • 只有脚本的 函数 会被原生编译。顶层外部 作用域 中的代码通常只执行一次,因此没有像被多次调用的函数那样受益,尤其是那些每帧都被调用的函数。

  • 建议您测量脚本或函数在启用和未启用原生编译时所需的时间,以判断何时最好使用它。 脚本分析器 工具可以测量函数的性能,以便做出明智的决策。

  • 可能会有诱惑在 每个 脚本中放置 --!native 注释,以防其中一些会更快地执行,但原生代码生成有一些缺点:

    • 需要代码编译时间,这可能会增加服务器的启动时间。
    • 额外的内存被占用以存储原生编译的代码。
    • 游戏中允许的原生编译代码的总量有限。

通过明智地使用 @native 属性,可以解决这些问题。

避免的代码

虽然所有功能在启用或未启用原生代码生成时的行为相同,但其中一些将无法以原生方式运行,并可能导致去优化或回退到解释执行。这些包括:

  • 使用已弃用的 getfenv()/setfenv() 调用。
  • 使用各种 Luau 内置函数,如 math.asin(),并传递非数值参数。
  • 向类型函数传递不正确类型的参数,例如在 foo 被声明为 function foo(arg: string) 时调用 foo(true)。请记住始终使用正确的 类型注释。

在使用 脚本分析器 时,您可以比较常规版本的函数与原生编译版本所需的时间。如果在 --!native 脚本或标记为 @native 的函数中未显示原生执行,可能是由于上述列表中的一个或多个因素触发了去优化。

使用类型注释

原生代码生成尝试推断给定变量的最可能类型,以优化代码路径。例如,假设 a + b 是在数字上执行的,或者在 t.X 中访问一个表。然而,由于运算符重载,a 和 b 可能是表或 Vector3 类型,或者 t 可能是 Roblox 数据类型。

虽然原生代码生成将支持任何类型,但错误的预测可能会触发不必要的检查,从而导致代码执行变慢。

为了解决一些常见问题,Luau 会检查函数参数上的类型注释,但特别建议对 Vector3 参数进行注释:

--!native
-- "v" 被假定为一个表;由于表检查,函数执行较慢
local function sumComponentsSlow(v)
return v.X + v.Y + v.Z
end
-- "v" 被声明为 Vector3;为向量生成的代码是专门化的
local function sumComponentsFast(v: Vector3)
return v.X + v.Y + v.Z
end

Studio 工具

以下 Studio 工具支持 --!native 脚本和 @native 函数。

调试

支持脚本的一般 调试,但局部/上值的视图可能不完整,并且缺少正在原生执行的 调用栈 帧中的变量。

还请注意,当调试选定为原生编译的代码时,放置 断点 将禁用这些函数的原生执行。

脚本分析器

在 脚本分析器 中,原生执行的函数旁边会显示 <native>:

脚本分析器中标记为原生的函数示例

如果标记为 @native 或在 --!native 脚本中的函数未显示 <native> 注释,则该函数可能由于 断点 放置、使用 不推荐的代码 或不匹配的 类型注释 而未以原生方式执行。

Luau 堆

在 Luau 堆 分析器中,原生函数占用的内存在图表中显示为 [native] 元素。

Luau 堆分析器中标记为原生的内存使用示例

大小分析

每个原生编译的脚本都会消耗内存。当编译代码的大小达到预定义限制时,原生编译将停止,剩余代码将以非原生方式运行。这使得仔细选择脚本进行原生编译变得至关重要。

要监控单个函数和脚本的原生代码大小:

  1. 确保您通过 客户端/服务器切换 按钮处于 服务器 视图。
  2. 从 命令栏 调用 debug.dumpcodesize()。

在 输出 窗口中,您将看到在调用时已原生编译的脚本和函数的总数、它们的原生代码所消耗的内存以及原生代码大小限制。随后,您将看到每个原生编译脚本的代码大小按降序排列的表格。

输出窗口中显示的原生代码大小示例。

对于每个脚本,输出显示已编译的函数数量和原生代码内存消耗。然后按原生代码大小降序列出每个函数,匿名函数显示为 [anonymous],整个脚本显示为 [top level]。在最后一列中,计算出相对于原生代码大小限制的百分比。请注意,函数的原生代码大小报告是精确的,但脚本的内存消耗四舍五入到最近的页面大小。

限制和故障排除

将代码编译为特定 CPU 的指令需要额外的存储内存。此外,复杂函数的优化可能需要花费太多时间。达到内部限制将在 Studio 的 输出 窗口中报告错误,包括:

函数 'f' 在第 20 行超过单个代码块指令限制

此错误意味着函数内部的单个代码块使用了超过 64K 的指令。可以通过简化函数或将其拆分为单独的小函数来避免此问题。

函数 'f' 在第 20 行超过函数代码块限制

此错误意味着单个函数包含超过 32K 的内部代码块。内部代码块并不完全映射到脚本中的控制流块,但可以通过简化函数中的控制流或将其拆分为单独的小函数来避免此错误。

函数 'f' 在第 200 行超过总模块指令限制

此错误意味着该函数的总指令数达到了整个脚本的 100 万指令限制。在某些情况下,报告的函数本身可能有很多指令,或者该限制可能是由脚本中较早的函数达到的。为避免此问题,建议将特别大的函数移到单独的非原生脚本中,或在其他函数上使用 @native。您还可以尝试用 --!native 标记该单独脚本,但 100 万指令占用大量内存,您可能会超过内存限制。

函数 'f' 在第 20 行遇到内部降低失败 (或)
内部错误:原生代码生成失败(汇编降低)

有时,函数包含原生代码编译器当前无法处理的复杂代码。为避免此错误,请检查代码中的复杂表达式并将其拆分或简化,但也可以考虑打开一个错误报告,附上因这个原因失败的代码示例。

已达到原生代码生成的内存分配限制

此错误意味着已达到原生代码数据的整体内存限制。为避免此问题,请尝试从内存占用较大的脚本中删除 --!native,以允许更多较小的脚本适应限制。或者,将大型或不常调用的函数移到单独的非原生模块中。

©2026 Roblox Corporation、Roblox、Roblox 标志及 Powering Imagination 是我们在美国及其他国家或地区的注册与未注册商标。