0

Is this assetbundle loader script can be the source of my game's leak memory problem? Is caching the AssetBundle-object bad?

public class AssetLoadWrapper{
    public static Dictionary<string, AssetBundle> cacheBundle;
    public static HashSet<string> assetLock;

     public static IEnumerator loadAsset<T> (string path, System.Action<T> onFinished, bool isAssetBundle = false) where T:UnityEngine.Object {
        //doing locking mechanism if one want to access currently the same asset
        if (assetLock == null)
            assetLock = new HashSet<string> ();
        while (assetLock.Contains (path)) {
            yield return 0;
        }
        assetLock.Add (path);

        //check if the path pointing to assetbundle or just loading to Resource folder
        if (isAssetBundle) {

            //cache initialization
            if (cacheBundle == null) {
                cacheBundle = new Dictionary<string, AssetBundle> ();
            }

            //check if assetbundle already in the cache, if yes, then just load the main asset from the cache
            if (cacheBundle.ContainsKey (DataManager.GetCachePathForAsset () + "/assets/" + path + ".unity3d") && cacheBundle [GaritaDataManager.CachePathForGarita () + "/assets/" + path + ".unity3d"] != null) {

                AssetBundle temp = cacheBundle [DataManager.GetCachePathForAsset () + "/assets/" + path + ".unity3d"];
                //the main asset is the one what I want to load in game scene
                T tempData = temp.mainAsset as T; 
                temp.Unload (false);
                //return the asset via callback
                if (onFinished != null)
                    onFinished (tempData);
            } 
            // if the assetbundle is not in the cache
            else {
                //check if the assetbundle .unity3d exists on the local disk
                bool exists = System.IO.File.Exists (DataManager.GetCachePathForAsset () + "/assets/" + path + ".unity3d");
                byte[] bytes = null;
                if (exists)
                    bytes = System.IO.File.ReadAllBytes (DataManager.GetCachePathForAsset () + "/assets/" + path + ".unity3d");

                //if not exist, then just callback with the null data
                if (bytes == null) {
                    onFinished (null);
                    LogUtil.Error ("LoadAsset", "bytes = null => " + DataManager.GetCachePathForAsset () + "/assets/" + path + ".unity3d");

                    //remove the lock
                    assetLock.Remove (path);
                    yield break;
                }

                //create assetbundle from the memory
                AssetBundleCreateRequest www = AssetBundle.CreateFromMemory (bytes);
                www.priority = int.MaxValue;
                while (!www.isDone) {
                    yield return 0;
                }

                //if it is valid assetbundle
                if (www.assetBundle != null) {
                    T data = www.assetBundle.mainAsset as T;

                    //cache the main asset to the cache
                    if (!cacheBundle.ContainsKey (DataManager.GetCachePathForAsset () + "/assets/" + path + ".unity3d"))
                        cacheBundle.Add (DataManager.GetCachePathForAsset () + "/assets/" + path + ".unity3d", www.assetBundle);
                    else
                        cacheBundle [DataManager.GetCachePathForAsset () + "/assets/" + path + ".unity3d"] = www.assetBundle;

                    //since i just need the main asset, i dont need another asset, i just pass "false" to assetbundle.unload method
                    //and the responsibility if the main asset is needed or not, is passed on to the one who needs this asset.
                    // i am assumming that if i dont needed the asset anymore, i just set the reference to the assetbundle data to 
                    // null, and calling Resources.UnloadUnusedAsset() respectively in order to free the memory

                    www.assetBundle.Unload (false);
                    if (onFinished != null)
                        onFinished (data);
                } else {
                    LogUtil.Error ("LoadAsset", "www.assetBundle = null => " + DataManager.GetCachePathForAsset () + "/assets/" + path + ".unity3d");
                    if (onFinished != null)
                        onFinished (null);
                }
            }
        } else {
            Object t = Resources.Load (path);
            if (onFinished != null)
                onFinished (t as T);
        }
        assetLock.Remove (path);
}
Agung Pratama
  • 3,666
  • 7
  • 36
  • 77

1 Answers1

0

I see you've unloaded "unused" assets but not used assets. When you're done using the assets from the asset bundle you have to unload the asset bundle with the "true" flag. This is documented here: http://docs.unity3d.com/ScriptReference/AssetBundle.Unload.html

DuMaiKe
  • 66
  • 6
  • Yes, that is for caching purpose by the way. And I already got the solution where designing how the asset is populated is the key here, such as use proper atlas management, use LRU cache principle. – Agung Pratama Aug 23 '15 at 03:01