效能與除錯

效能模型

每幀每實例的成本結構:

環節成本
快照搬運處理(宿主 → 模組)唯一強制的 Java 穿越:宿主用可複用的建構器把 POD 快照寫進共享頁 / 直接緩衝區
資料讀取(Vehicle / Pids / …)普通記憶體讀取,零成本
繪製記錄寫入記憶體區內以 bump 方式配置,零額外配置、零裝箱
像素光柵(Gfx2D)純 C++ 迴圈;src-over 不透明快速路徑
宿主回放與 JS 相同的渲染路徑;紋理上傳只搬運髒矩形
Api 呼叫JSON 編碼 + 反射 + JSON 解碼往返——昂貴 只作低頻通道

熱路徑守則

  1. render 裡不碰 Api。高頻資料全在快照裡;高頻繪製全走記錄流。JS 時代的週期性 GC 卡頓正是「每幀每車一次反射呼叫」造成的。
  2. 資源只在 create 時建立:模型、紋理、Java 物件控制代碼、回呼——建好存入 State,render 只用。
  3. 避免每幀資源讀取 / HTTP:網路請求丟進 BackgroundWorker,結果放進你自己的同步快取,render 讀快取。
  4. 紋理只在內容變化時上傳:靜態背景畫一次;動態內容用 push_clip 限定重繪範圍,讓髒矩形只覆蓋真正變化的條帶。
  5. 逐物件錯相:多實例輪播 / 閃爍不要同幀齊動——用相位錯開的排程讓髒區分散到不同幀(以 in_game_time() 或 game_time_millis() 當時鐘)。
  6. 字串暫存物件要節制:StrView 比較免複製;確實要串接時注意 std::string 的配置(短字串 SSO 免配置)。

記憶體與延遲回收

宿主側的記憶體紀律(腳本作者了解即可,SDK 自動受益):

  • 五個輸出記憶體區每模組一份、幀間複用;像素記憶體區初始 1 MB、按需增長(上限 16 MB)、尖峰過後確定性收縮回下限——不再有每模組 16 MB 的固定駐留。
  • 實例離開視錐不銷毀(原樣保留、重新入鏡零重建);真正離開用戶端車輛清單約 5 秒後才回收。
  • 大塊釋放走 defer_free(ABI 10):在 render / dispose 裡死亡的上百萬位元組緩衝交給宿主背景回收執行緒,避免把 free 的全部成本計到目前幀、並放大 GC 安全點等待。契約:區塊必須已死、無解構、此後無任何執行緒(含宿主回放)再碰觸。SDK 的像素記憶體區收縮已自動遵守;你自己的大緩衝按同樣規則呼叫 host->defer_free,宿主過舊(槽位為 null)時同步 free 即可。

觀測與日誌

看什麼在哪裡內容
模組 censuslogs/latest.log 啟動段落已載入模組數與類型;傳輸通道摘要行(含 transport: 字樣:shared-memory / panama-ffm 等)——確認 shm / FFM 真正生效、是否靜默降級
載入失敗原因census 行 + 除錯模式某一側(JS 或 C++)缺失 / 載入失敗只跳過該側並留下提示,另一側照常工作
崩潰防護latest.lognative script faulted: code=… module disabled——模組被停用的精確原因
清掃流量latest.log(每分鐘一行)實例銷毀節奏的彙總日誌,可直接觀測實例壽命行為
上傳位元組數GraphicsTexture::last_upload_bytes()在你的程式碼裡打點:髒矩形策略是否奏效一目瞭然

改完程式庫按 F3+T(或模組的「重新載入全部 MTR 腳本」快速鍵)即可重新載入 C++ 腳本——卸載與重新探索走完整流程,無需重新啟動遊戲。

JVM 參數

參數預設作用
-Djcm.nativeIdleMillis90000實例仍存在但長期未渲染時,超過該毫秒數才釋放;0 = 不按時間限制釋放
-Djcm.nativeIdleMax32熱實例上限,超出時按最久未渲染者優先釋放;0 = 不設上限
-Djcm.ffm.disable關除錯開關:停用 Panama FFM 載入路徑

實例回收與銷毀還有每 tick 預算(預設 2 個、舊者先出)與世界卸載 / 切換維度 / 斷線時的一次性排清。

常見問題

模組完全不載入?

  1. 確認用的是 Release 或 Complete Build jar——快速 CI 產物不含原生橋,日誌會寫 native bridge unavailable(這不是你的模組的問題)。
  2. 查平台目錄:目前系統只會載入對應平台的程式庫;無副檔名的 stem 宣告會自動展開為各平台路徑(見打包)。
  3. 查 ID 與宣告條目的 id 是否逐字一致。
  4. 查 ABI:宿主接受 6–11;ABI 8+ 程式庫需要 2.3.0-beta-2.yanyang.7 及以上宿主。

螢幕出現佔位方框(tofu)?

CJK 字形在宿主字型未涵蓋該碼點時退化——給 Text::font() / Gfx2D 建構子傳資源字型 id(如 jsblock:shanghai),或檢查所用字型集是否包含這些字元。

偶發掉幀?

  • 先看是不是「每幀整螢幕重繪」:靜態內容畫一次、動態內容以 clip 條帶重繪,用 last_upload_bytes() 驗證。
  • 再看是不是多實例同幀齊動:輪播 / 閃爍 / 開門動畫逐物件錯相。
  • 最後查有沒有 render 裡的 Api 呼叫(包括間接的:ctx.set_auto_z_ordering 等個別上下文方法在 ABI 8+ 會轉發一次)。

Windows 上行為和別處不一樣?

ABI 6 之前的歷史版本曾依賴「零填充記憶體可直接當物件用」——這恰好只在 MSVC 佈局下倖存。目前 SDK 的 mtrInit() 契約已根治;如果你在寫自訂宿主,務必在配置狀態區塊後呼叫 mtrInit()。


回到:文件首頁。