原生代码生成

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

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

启用原生代码生成

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


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

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

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


@native
local function f(x)
return (x + 1)
end
1 将来,如果某些脚本确定会获得收益,可能会自动开始以原生方式运行,但目前仍需手动放置 --!native 注释。

最佳实践

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

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

  • 只有脚本的 函数 被原生编译。顶外 作用域 中的代码往往只执行一次,因此无法像多次调用的函数那样获得更多收益,尤其是那些每帧调用的函数。

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

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

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

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

避免的代码

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

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

在使用 脚本性能分析器 时,您可以比较普通版本的函数与原生编译版本的执行时间。如果在 --!native 脚本或用 @native 标记的函数内没有原生执行,一个或多个上述列表中的因素可能会触发去优化。

使用类型注解

原生代码生成尝试推断给定变量的最可能类型,以优化代码路径。例如,它假设 a + b 是在数字上执行,或者假设表在 t.X 中被访问。然而,考虑到操作符重载,ab 可能是表或 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 Heap 性能分析器中标记的原生内存使用示例

大小分析

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

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

  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 是我们在美国及其他国家或地区的注册与未注册商标。