效能與除錯

效能模型

每幀每實例的成本結構:

環節成本
快照搬運處理(宿主 → 模組)唯一強制的 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 裏死掉的 MB 級緩衝區交給宿主背景回收執行緒,避免把 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()。


回到:文件首頁。