Search Unity

Should I use 1 AssetBundle or 100?

Discussion in 'Asset Bundles' started by sarahnorthway, Jan 22, 2021.

  1. sarahnorthway

    sarahnorthway

    Joined:
    Jul 16, 2015
    Posts:
    53
    I have a visual novel style game with 100 very large (3840x2160, 40mb in ram) jpgs. I only need to display one at a time, and don't want the rest hanging out in ram. The images are displayed in random order.

    Would I want to use 100 AssetBundles, each one containing one jpg?

    Or 1 AssetBundle containing a hundred jpgs?

    Or should I put them in 10 groups of 10 (alphabetically...?).

    Also please convince me that using a Resources folder is a worse solution than either of these... I can tell that Unity really really hates Resources folders, but I'm not sure how it actually differs from one big AssetBundle.
     
  2. sarahnorthway

    sarahnorthway

    Joined:
    Jul 16, 2015
    Posts:
    53
    The manual goes on about logical groupings, and the tutorial's section on Asset Assignment Strategies states:

    • Having too few AssetBundles...
    • Increases runtime memory usage
    • Increases loading times
    • Requires larger downloads
    • Having too many AssetBundles...
    • Increases build times
    • Can complicate development
    • Increases total download time

    So I understand it's an important decision and ideally I should know which Sprites are coming up next and bundle them together (I can't). But in my simple case which is better, one giant AssetBundle (functionally identical to a Resources folder?) or a ton of smaller ones?

    I am leaning toward using a Resources folder.
     
  3. kavalri_patrik

    kavalri_patrik

    Joined:
    Dec 18, 2020
    Posts:
    31
    If you use chunk based compression when building your asset bundles, Unity will be able to load individual assets from the bundle without loading the whole bundle into memory. AssetBundle.LoadFromFile() will only load the bundle's header, leaving the actual contents on disk. The assets are decompressed and loaded into memory on the fly when you request them. They can be unloaded by calling Resources.UnloadAllUnusedAssests() after you're done using them (or by simply loading another scene non-additively). This makes it feasible to put all your assets into a single bundle.

    The upsides of doing that are:
    • No need to worry about things like bundle dependencies and asset duplication.
    • Easy development - just put everything in the one bundle.
    However, it's a limited solution:
    • You'll have to ship all your content in a single file, either included in the build (StreamingAssets folder) or as a single large post-install download.
    • You can't selectively unload assets: your only option is to unload all unused assets. If your assets are ordered into bundles you can choose which bundles to unload.
    Also, I'm quite sure that the statement about increased build times with many asset bundles is wrong. They actually speed up build times, because they do not need to be rebuilt unless the assets have changed (provided you keep building your asset bundles to the same folder and retain the ones from previous builds). If you have all your assets in a single bundle, you'll have to rebuild all of it every time a single asset is changed. Of course, going too extreme in either direction is bad, as I'm sure at some point the overhead of building many bundles will outweigh the gains. But I'd guess that only starts becoming relevant if you put very few and small assets in each bundle.

    If I were you I'd put the images in one bundle each. If you do that, you'll probably also want to consider using regular zip-compression instead of chunk-based compression - that'll give you better compression ratio. You'll then have the benefits that:
    • You can choose to download some of the bundles after the app is installed instead of including them with the binary.
    • You'll have full control over what's in memory at any time: load a bundle when you need it, unload it when you don't need it.
    • If you edit one image and rebuild the app, only a single bundle will need to be rebuilt - quick iteration times.
    As a final note: the more assets that go into a single bundle, the better the compression ratio will tend to be. If app size is important to you, you may need to consider grouping assets together in larger bundles to reduce the total size.

    Edit: in case it wasn't clear, you'll absolutely want to stay away from using regular zip-compression and putting all assets in a single bundle - this will result in all assets being loaded into memory simultaneously.
     
  4. sarahnorthway

    sarahnorthway

    Joined:
    Jul 16, 2015
    Posts:
    53
    I am not building for mobile, so compression ratios, post-install downloads, and choosing when to download bundles is irrelevant to me (but good to know!). I also won't be editing these files regularly, so rebuild times don't matter. This is very useful info re: different compression method behaviors. But what really caught my eye is this:
    • You can't selectively unload assets: your only option is to unload all unused assets. If your assets are ordered into bundles you can choose which bundles to unload.
    So you're saying that while partial contents of bundles can be loaded (one file at a time from a bundle of 100 files), the can't be UN-loaded partially? Like, the Sprites won't be garbage collected after I remove all references to them and call Object.Destroy on them?

    I display 2 images at a time in order to fade between them, so there is no time that I could unload ALL the images at once. So you're saying if I used a single Asset Bundle, the file references would pile up in ram until all 100 images were loaded and/or the game crashed?

    Resources folders don't work this way, in my experience, making it a superior solution to a single Asset Bundle.
     
  5. kavalri_patrik

    kavalri_patrik

    Joined:
    Dec 18, 2020
    Posts:
    31
    You can still unload unused assets by calling Resources.UnloadUnusedAssets(). So, if you call Resources.UnloadUnusedAssets() between loading each of your sprites, the ones which are no longer in use will be removed from memory. If you call it every time you fade to another sprite you'd have at most 2 sprites in memory at any time.

    However, it's not possible to unload a specific asset directly, you can only unload specific bundles. Object.Destroy() can't be used to unload a loaded asset from memory, it can only destroy instantiated copies of them. If you want to be able to do that, you need to put your asset in a bundle. Then you can unload the asset by unloading the whole bundle. I don't know why it works like this, I think it would be great if Unity allowed us to unload single assets manually.

    I know Unity explains all this somewhere, but couldn't find the exact spot. I did however find this link about memory management in the Addressables system, which is based on asset bundles: link. The paragraph at the bottom sums it up nicely: "You can load an asset bundle, or its partial contents, but you cannot partially unload an asset bundle. No asset in 'stuff' will unload until the bundle itself is completely unloaded. The exception to this rule is the engine interface Resources.UnloadUnusedAssets."

    In most cases, Resources.UnloadUnusedAssets() gives you enough control over memory usage. For you, it sounds like it would be enough. The more fine-grained control given by asset bundles starts to become necessary when you have situations like "I need to clear out some memory, but I know that some of these assets will soon be needed again, so I don't want to unload everything that's currently unused.". For example, in an open-world type game, you might want to unload assets that are very far away from the player, whilst keeping those which are close.
     
  6. sarahnorthway

    sarahnorthway

    Joined:
    Jul 16, 2015
    Posts:
    53
    Aha, gotcha! Yeah so if I did want to use a single bundle but keep something around to instantiate later, I'd hold a reference to it while calling Resources.UnloadUnusedAssets().

    Thank you!
     
  7. ProdiggaPA

    ProdiggaPA

    Joined:
    Nov 29, 2019
    Posts:
    11
    If you have time, you should run a few quick tests and report back to results. I am curious myself!
     
  8. mahdi_jeddi

    mahdi_jeddi

    Joined:
    Jul 18, 2016
    Posts:
    210
    Another benefit of using multiple asset bundles is patching the game. Although Steam does fine-grain patching, it's not perfect and some other platforms don't support it.

    Off topic: One trick I learned for one of the games with comics-style cutscenes was to add every sprite to a sprite atlas even if it's a huge image. That way it will be forced into power of 2 images that compress a lot better in memory. Your 3840x2160 images would be turned into 4096x4096 textures that now can use proper image compression and be a lot smaller (4x-8x) while in memory.
     
    sarahnorthway likes this.
unityunity