- Home /
UnloadUnusedAssets - Causing Loss of Used Assets
Hello,
Has anyone heard of this happening? When I call 'UnloadUnusedAssets' my app gets odd affect of textures disappearing, or being replaced completely.
The app is a Cartoon Comic book, each page is a prefab that is dynamically loaded via Resource.LoadAsync, and then unloaded when the Page isn't being viewed anymore.
The idea for this method is to reduce memory load as each page contains high quality textures which will crash the app if all are loaded in at startup. (for iOS).
This is how I load a page in:
var request : ResourceRequest = Resources.LoadAsync( GetPrefabName(lindex) );
while(request.isDone == false)
yield;
loadedPrefab = Instantiate(request.asset) as GameObject;
So, the problem is, when I try and unload a page like so:
Destroy(scene);
yield WaitForEndOfFrame();
Resources.UnloadUnusedAssets();
System.GC.Collect();
It works fine, the system memory is decreased. But a couple of textures throughout the app are now missing, or have been completely replaced by a random texture, not only that but my Texture Renders will sometimes 'untarget' themselves from the page camera (it's what I use to render my comic page). Whats odd though, is that these 'missing' textures are within other dynamically loaded pages (prefabs), meaning the app has to load in everything onto memory anyway, yet the texture may still be incorrect.
Can anyone explain this please? Thanks.
Answer by Meic · May 14, 2016 at 01:10 PM
Hi. Firstly, the issue seems to appear on Android as well - that's the platform I am working with. Secondly, apparently the problem is not just UnloadUnusedAssets thing, but more like unloading and loading assets at the "same time" issue. It means that when you instantiate some asset and have unloading activity running, the instantiated object is gonna be corrupted in some way (in my case I got, e.g. empty ngui atlases - there's no difference between loading form Resources and loading from asset bundles).
The solution in my case was creating dedicated class that is managing loading and unloading assets. The assets can be instantiated only when there is no unloading unused assets in progress (so I use unload with yield) and unloading can be started only when there is no asset loading in progress.
I'm using Unity 5.3.4 and after separating mentioned above loading and unloading mechanisms the problem seems to be solved.
Answer by sandolkakos · Dec 15, 2015 at 06:54 PM
Hi @oliver-jones I recommend you to use Resources.UnloadUnusedAssets() with the yield keyword inner a Coroutine, like this:
IEnumerator LoadNewAssetsRoutine ()
{
// Destroy your objects.
yield return Resources.UnloadUnusedAssets();
// Continue executing new actions and loading new objects.
}
Thanks, but that still doesn't explain why it would remove textures that are indeed being used elsewhere in my scene.
I was facing this problem too, and after use Resources.UnloadUnusedAssets with the yield keyword, the problem does not happened again.
I "think" the app need to wait for the Resources.UnloadUnusedAssets conclude all actions before try to load more assets, otherwise these new assets can be uloaded by the Resources.UnloadUnusedAssets which is still running.
sorry my bad english...
Thanks for your help - I'm still having the same problem though. I may have narrowed down what is causing it:
Once a scene is loaded in via Rosoruce.Load - The app then dynamically generates a bunch of Texture2ds, and then Destroys them all except one.
This issue I'm having doesn't occur if I prevent the app from generating these image. Would this generation of Textures cause some kind of mixup when using UnloadUnusedAssets?
Answer by oliver-jones · Jan 03, 2016 at 02:49 PM
I may have solved my issue. I still need to do more internal tests - but it appears to work so far. So what I was doing was loading in a Prefab, and then Destroying that Prefab (GameObject), and then calling Resource.UnloadUnusedAssets, which theoretically should work fine. But those texture issues started appearing.
So I also get all GameObjet components within all the children on that prefab, and Destroy that too:
//instead of destorying entire prefab - cycle through children and destory them one by one
children = scene.GetComponentsInChildren.<Transform>();
print("[SERIAL] Object Count: " + children.length);
for(i = 0; i < children.length; i++){
Destroy(children[i].gameObject);
}
//then destory prefab scene too
Destroy(scene);
//remove resources
yield WaitForEndOfFrame();
yield WaitForEndOfFrame();
yield Resources.UnloadUnusedAssets();
Debug.LogWarning("[SERIAL] Collecting Garbage");
System.GC.Collect();
Like I said, it appears to be working okay now! Not sure why?!
--- UPDATE ---
This method doesn't actually work, I can confirm.