- Home /
Unity 5 Asset Bundles limitations for mobile platforms.
I've got a question about the limitations of Unity 5 Asset Bundles for mobile platforms. As it was said in one of the official training videos ( https://www.youtube.com/watch?v=6D9AbQodeVg&feature=youtu.be&t=30m56s ), asset bundle cannot be loaded, unloaded and loaded again in one scene. I assume that it's true (the mentioned video was the only place I found such limitation described). And if it's, does it mean the loaded asset bundles must be present in memory as long as they may be requested by game (so it's like 'load once and unload only on scene change')?
To make clear what I'm about let's imagine following situation.
We are creating mobile game using some memory expensive assets (let's say they are dialogs - they can be used anytime when the game is running but thay cannot be all kept in memory due to relatively low memory amount available). To prevent keeping them in memory all the time, we are storing them as a prefabs placed under 'Resources' folder. We can use Resources.Load to load them and Resources.UnloadUnusedAssets to unload when it's necessary. In this approach we can control memory usage and are able to use any assets when they are required.
Now, according to asset bundles' limitations mentioned in the video, is it possible, to use bundles instead of 'Resources' folder and still be able to keep in memory only assets that are realy necessary at the moment?
I've been watching the video yesterday and I heard the same thing. I see we're not the only one with this use case. I'll be glad to know more about this limitation because as for now I did tests on iOS which involved loading an asset bundle, unloading it, clearing cache (which is a different story I know but... well), reloading it and it worked perfectly fine. Of couse at that time I supposed it was indeed unloaded... now I'm unsure... I need to watch the memory footprint more closely to confirm this... that was not a heavy asset bundle though so it might have stayed in memory without me noticing it. Anyway I just did reload and it kind of worked... or looked like. $$anonymous$$eanwhile, I'll be testing that again with more heavy bundles...
By the way, in my test I instantiated some assets loaded from the bundle,then I am destroying them via Destroy and the corresponding assets via DestroyImmediate(asset, true) but also had to use a Resources.UnloadUnusedAssets(); to see the memory go down to its pre-assetbundle loading/instantiating level... Am I completely off there or...?
Answer by Mike-Geig · May 11, 2015 at 04:14 PM
EDIT 10/28/2016: Due to some confusion on my original post, I wanted to clear up and explain a few points and to identify a few things that have changed (much of this is verified here, I'm just summarizing). Here are somethings to keep in mind:
1) Prior to Unity 5.3, all ABs (Asset Bundles) where compress all together using LZMA. This means that they needed to all be uncompressed together in order to access anything out of it. In 5.3, we added LZ4 compression. Now you only uncompress a single item out of an AB instead of the whole thing (reducing memory overhead)
2) LoadFromMemoryAsync (previously called CreateFromMemory) should not be used unless absolutely needed. Using this will double your memory overhead. Those of you reporting 2x memory usage, this may be why.
3) AssetBundle.LoadFromFile is what I describe below and should be the method you try to use whenever you can. This has a very low memory overhead, however, profiling in the editor will behave like AssetBundle.LoadFromMemoryAsync and this will report double memory overhead. This does not mean it is actually using that much memory on device and you should do all of your memory profiling on device to verify.
4) Using WWW.LoadFromCacheOrDownload to pull down ABs has additional memory overhead. This is due to a requirement of the WWW class. Not much can be done about that except...
5) In 5.3 AssetBundleDownloadHandler was added for mobile platforms. This works the same as the WWW class but it is much better at managing memory usage on mobile. Use this for better performance.
If you find you are getting major extra memory issues, definitely check the above points and ensure you are using the best setup possible. Otherwise, you could always be experiencing a bug and you should let us know. Now, without further ado, here is the original answer:
Original Answer: Howdy, basically the limitation revolves around what happens if the mobile OS flushes the memory cache and your bundle is unloaded. I misrepresented the issue in the video a little bit (tough to recall everything while live). So here is the problem laid out:
1) You load a bundle
2) You load a texture from the bundle
3) You unload the bundle (everything fine so far)
4) The OS flushes memory (you have no control here)
5) Unity would naturally just regrab the texture for you, but you've unloaded the bundle (invalid texture error)
To circumvent this issue, on mobile, it is a good idea to only unload a bundle when you are sure that you are no longer using any assets from it.
Now, as far as the difference between bundles and resources folder, we have two situations:
1) Assets are in resources. They take space in storage and only take memory when the application needs them. They come packaged with game, are static, and increase install size.
2) Asset are in bundles. The bundles take space in storage and only take memory when an asset is loaded from a bundle. Loading a bundle loads the per object header data (minimal). They are not packaged with the game, are dynamic, and do not increase install size.
Hope this helps!
EDIT
I've had a request for more information regarding memory, so let me help clear that up with an edit. An asset bundle is a file that contains assets and information about those assets. So, when you load an asset bundle you are only loading the information about the assets into memory (which is very small). Then, when you load an asset from the bundle, the actual asset is then loaded into memory. So, it's not a memory usage of 1 + 1, but more like 1 + .00001. When you unload a bundle with false, the asset information is unloaded but the loaded assets stay in memory. When you unload with true, it's all purged from memory.
Oh dear, am I dumb? :) I'm not sure I understand: what do you mean by "just regrab the texture for you" when/in what circumstances? Wouldn't it be something to do with dependencies of a loaded asset ins$$anonymous$$d of an asset itself?
"so it's not the full memory footprint of the bundle" Ok I hope this is indeed the case so we can keep those around to make sure we don't have this nasty situation but still enjoying the advantage of a lower memory consumption.
Thank you, I'm still struggling with the asset bundle concept, mostly about the memory management behind it... I'm maybe using it in a way that's not really appropriate (I didn't have the occasion to try the older system by the way).
And keep up with the good training videos, I really enjoyed the clarity (well... ok not everything you said apparently :)) of your explanations!
Basically, if the OS wipes a texture out of memory, Unity will handle it for you (you don't have to do anything). That is, unless the texture is no longer available because you unloaded it.
Good rule of thumb, put related things into bundles together so you will never have a situation where you only need one item out of a bundle. So, if you need one item from a bundle, chances are you will need the rest of the items too and no overhead will be wasted.
Oh yes I'm sorry... was thinking about caching ins$$anonymous$$d of plain memory. As long as I keep the bundle in memory while I'm using the assets it should be okay then. Which brings me on the memory footprint of loaded asset bundle. I'll need to make tests to see if it's a problem. Thanks a lot $$anonymous$$ike.
To circumvent this issue, on mobile, it is a good idea to only unload a bundle when you are sure that you are no longer using any assets from it.
Wait, wait, wait, wait, wait...
It's my understanding that having a bundle loaded means having it's contents unzipped in memory. So, if I load 10 megs of textures from a bundle but don't unload the bundle, that means I've got 20 megs total in memory: 10 megs in OpenGL mem for actually drawing stuff and 10 megs in Unity-accessible CPU mem sitting idle in the loaded asset bundle.
Am I misunderstanding this? It sounds like you are saying that asset bundles will double the memory footprint of my assets unless I want to randomly crash on an OS memory warning.
Answer by eaguayo_sav · Sep 28, 2016 at 03:22 PM
I am going to have to disagree with the accepted answer above regarding memory usage. However it is correct regarding asset bundles reducing app size when compared to loading from the resouce folder.
As of, and maybe before, 5.3.4 it appears you will pay a non-trivial memory cost when an asset bundle is in memory. This cost appears to be a little larger than the compressed version of the bundle, which makes sense.
Note that for this test I'm using the default compressession setting (LZMA Format) and treating the content I am using as "DLC" downloaded after the fact and saved to disk.
The set up for the test was to create an empty scene with a canvas and two buttons. One would download an asset bundle of ~35MB from an Amazon S3 bucket and save it to member varible to avoid any GC issues, the other would call Unload on the bundle.
I let the app run for a few seconds to get a base line, then downloaded the bundle. After letting the app sit idle for a few more moments to get a new base line I pushed the button to unload.
When the bundle was loaded the Assets and Total Object Count increased by one (1) and memory increased ~40MB, slightly larger than the compressed file downloaded (see attached pic). After Unloading the bundle everything returned almost exactly to the pre-bundle load base line. It is important to note that memory peaked at an ~80MB increase up to 300MB total.
This seems to be backed up by the documentation regarding Loading and Unloading Bundles.
Like the question posed by @Meic, I'm building a mobile app with similarly expensive assets that are used in a context specific manner. Knowing from testing that on a lower end device, with 1GB of RAm for example, which includes the very much used iPad 2, allocating more than 100MB of assets on demand, on top of what it takes to run Unity's own resources and "normal" app levels of other assets/logic, will result in the app running out of memory and crashing.
To get around this I am planning on breaking my assets up into the smallest possible bundle. Caching the bundles to disk. Then when needed reading them from cache, loading the assets, then releasing the data read form disk with Unload(false). When I am done with the asset I will then release that as well. I am hoping that a mobile device will have enough memory to accomplish this.
I know we are great when using Resources.Load() and its unfortunate the bundle has to be brought into memory rather than just read from disk.
It is also worth noting that the LZ4 Format does allow for "random read" and does not require the full object to be decompressed. I need to experiment more to determine if that will results in a smaller foot print, because it can be read from disk directly for example.
Thanks for the info and the data to back it up. I think I see how your answer differs from $$anonymous$$e, but I don't want to assume. When you load the bundle and assign it to a variable, what exactly are you assigning to that variable? If you are accessing the file inside, it would only make sense that the whole thing was loaded into memory. If you're doing something different, perhaps you could post the code you are using.
I'm also not sure what you mean about the memory peaking at 80mb increase. Do you mean that if you load and then unload many times the memory usage keeps going up? I can't see from the screenshot where that number comes from. Thanks for the follow up! It is also possible that things have changed since I first posted this answer. I haven't used bundles in a while
After doing more digging I think most answers are found in these two these this section on the use of LoadFromCacheOrDownload and memory spikes and this section on using unitys newer UnityWebRequest system.
The "spike" I was talking about is the same one mentioned in this article which comes from the overhead of keeping the entire asset bundle btyes in the WWW request before writing to disk, then writing to disk. Both of which increase the memory heap.
Overall there are a lot of configuration concerns, such as your desired compression format, and ways to download a bundle that will vary upon platform needs. In low memory environments, such as mobile devices, in particular anything being downloaded it a possible app crasher.