Asset 管理 - FrankNine/franknine.github.io GitHub Wiki

原理

AssetDatabase

原理

YAML & Prefab

原理

AssetBundle

原理

Workflow

Load

  • AssetBundle.LoadAsset 前一定要先確認所有直接間接依賴到的 AssetBundle 都有讀取,否則會 dereference 失敗

    Because an Object is loaded when its Instance ID is first dereferenced, and because an Object is assigned a valid Instance ID when its AssetBundle is loaded, the order in which AssetBundles are loaded is not important. Instead, it is important to load all AssetBundles that contain dependencies of an Object before loading the Object itself. Unity will not attempt to automatically load any child AssetBundles when a parent AssetBundle is loaded.

    AssetBundle fundamentals

    AssetBundle 讀取順序不重要,但是讀出 Asset 瞬間 AssetBundle 依賴要齊全重要

  • Build AssetBundle 會產生 AssetBundleManifest,可以用 AssetBundleManifest.GetAllDependencies 取得某個 AssetBundle 所有需要的依賴(這個會回傳遞迴地依賴關係中 依賴依賴的依賴,API 命名有點糟難一眼看出是遞迴的,如果有特殊需求只需要一層的 直接依賴 是用 AssetBundleManifest.GetDirectDependencies

  • Scriptable Build Pipeline 產生的 Manifest 跟內建 Build Pipeline 不同,是 CompatibilityAssetBundleManifest,API 跟 AssetBundleManifest 相近但是 Dependency 回傳會包含自己,做 Reference counting 時要特別小心

  • Editor 環境可以用 AssetDatabase.GetAssetBundleDependencies 列出 AssetBundle 依賴

Unload

  • AssetBundle 讀出來的 Asset 不能單獨 Unload,官方提供的建議是將 AssetBundle 切小然後整個 AssetBundle.Unload

    We can instead create an AssetBundle for each prefab. These more granular AssetBundles alleviate the problem of large bundles retaining assets in memory that we no longer need.

    Tales from the optimization trenches: Saving memory with Addressables

  • 但是 AssetBundle 切小也有缺點

    • 讀取 AssetBundle 會讀出 SerializedFile 會需要兩個暫存 Buffer,照官方的說法

      • Two file read buffers
      • A type tree listing every unique type included in the bundle
      • A table of contents pointing to the assets

      These buffers are 64 KB each on PS4, Switch, and Windows RT, and 7 KB on all other platforms.

      Tales from the optimization trenches: Saving memory with Addressables

      每個開啟的 AssetBundle 會有 7K * 2 到 64K * 2 的記憶體 Overhead

    • 檔案多對檔案系統或是下載也會有負擔,如果下載走 HTTPS 沒辦法 Keep-Alive 重複利用 TCP 連線,重複交握的消耗也會可觀

  • Resources.UnloadAsset
    對 AssetBundle 讀出來的 Asset 無效

  • Resources.UnloadUnusedAssets
    對 AssetBundle 讀出來的 Asset 卻有效,但是不能控制範圍

    No asset in stuff unloads until the AssetBundle itself is completely unloaded. The exception to this rule is the engine interface Resources.UnloadUnusedAssets. Executing this method in the above scenario causes tree to unload. Because the Addressables system cannot be aware of these events, the profiler graph only reflects the Addressables ref-counts (not exactly what memory holds). Note that if you choose to use Resources.UnloadUnusedAssets, it is a very slow operation, and should only be called on a screen that won't show any hitches (such as a loading screen).

    Memory management: When is memory cleared?

  • 有人遇到 Addressable 下 Resources.UnloadUnusedAssets 無法移除已經沒有 Reference 的讀出來的 Asset,Unity 似乎已經修復(需要實驗確認)

  • AssetBundle.Unload(false) 有很多奇怪的行為,建議直接 AssetBundle.Unload(true) 自己修好會掉東西的地方,不要依賴 Unload(false) 造成的殘留效果

    • Unity 無法保證 Unload(false) 殘留的物件在手機上 App context switch 後持續可用

      If AssetBundle.Unload(false) is called, live Objects sourced from the unloaded AssetBundle will not be destroyed, but Unity will invalidate the File GUID and Local ID references of their Instance IDs. It will be impossible for Unity to reload these Objects if they are later unloaded from memory and live references to the unloaded Objects remain.

      Note: The most common case where Objects are removed from memory at runtime without being unloaded occurs when Unity loses control of its graphics context. This may occur when a mobile app is suspended and the app is forced into the background.

      Assets, Objects and serialization

拆解工具

工具資源

Addressable

獨立管理系統