原生程式碼生成

*此內容是使用 AI(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 堆剖析器中標記的原生內存使用示例

大小分析

每個原生編譯的腳本都會佔用內存。當編譯代碼的大小達到預定限制時,將停止原生編譯並以非原生方式運行剩餘的代碼。這使得謹慎選擇腳本進行原生編譯至關重要。

要監控單個函數和腳本的原生代碼大小:

  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 是我們在美國及其他國家地區的部分註冊與未註冊商標。