Why and How I Refactor My AssetBundle Manager
Comparing to putting asset inside of Resources
folder, using asset bundle system has a lot of benefits. While using resources system, Unity engine will create a index table for all resources inside Resources
folder, in order to fasten the speed of Resources.Load
. It is really fast but every time we add something into the folder, engine will need to rebuild the table, as the number of resources increase, the table also increase and need a lot of memory. By using asset bundle, we can load asset bundle manually, so compare to resources system, we usually get a faster launch time and a fast enough asset loading time. But here comes the problem, we need to manually manage the bundle.
The most popular operation with asset bundle are Load
and Unload
, synchronously or asynchronous, so these API are involved:
- LoadFromFile
- LoadFromFileAsync
- LoadFromStream
- LoadFromStreamAsync
- Unload
- UnloadAllAssetBundles
- LoadAsset
- LoadAssetAsync
(LoadFromMemory and LoadFromMemoryAsync are bad in practice because the data is stored redundantly in three location: The memory that store the binary data, the stack and the asset itself.)
The first 6 API are toward asset bundle and the last 2 are toward asset, my new solution is create asset bundle handler, it contains:
- Asset bundle itself
- Reference count
- A list storing all asset handler of this bundle that have been load, for asset handler, it contains:
- Asset it self
- Reference count
Every time I call my LoadAssetSync
or LoadAssetAsync
function, the manager checks if the asset bundle is loaded, if not, load it. It doesn’t increase the reference count until the asset is loaded. Once the asset is loaded, we increase the reference count for asset bundle handler and asset handler.
For unload, notice that the asset cannot be unload individually, the API Resources.Unload
is for asset that loaded though resources system, so I only decrease the reference count of asset handler, when it hits 0, also decrease the reference count of asset bundle handler by 1. My asset bundle will only be unload when the reference count becomes 0 or UnloadAllAsetBundles
is called, when switching scene.
When I implementing this system, I was thinking to combine RAII with this manager, as we need to unload asset manually, which is quite unsafe. However, we cannot destroy object (not gameobject) by C#
, we might also want to reuse the asset a period of time after loaded, so I decide to believe the garbage collection of C#
and the programmer who use this manager.