I am loading and Caching Asset Bundles using below function in unity webgl:
IEnumerator DownloadAndCacheAB(string assetName)
{
// Wait for the Caching system to be ready
while (!Caching.ready)
yield return null;
// Load the AssetBundle file from Cache if it exists with the same version or download and store it in the cache
using (WWW www = WWW.LoadFromCacheOrDownload(finalUrl, 1))
{
yield return www;
if (www.error != null)
{
Debug.Log("WWW download had an error:" + www.error);
}
AssetBundle bundle = www.assetBundle;
if (assetName == "")
{
GameObject abObject = (GameObject)Instantiate(bundle.mainAsset, gameObject.transform.position, gameObject.transform.rotation);
abObject.transform.parent = this.transform;
SetTreeShaderSettings(abObject);
}
else
{
GameObject abObject = (GameObject)Instantiate(bundle.LoadAsset(assetName), gameObject.transform.position, gameObject.transform.rotation);
abObject.transform.parent = this.transform;
}
// Unload the AssetBundles compressed contents to conserve memory
bundle.Unload(false);
} // memory is freed from the web stream (www.Dispose() gets called implicitly)
}
And whenever I want to remove the object i use this function.
public void RemoveBundleObject()
{
//if (www != null)
//{
// www.Dispose();
// www = null;
if (loadBundleRef != null)
{
StopCoroutine(loadBundleRef);
}
if (this.gameObject.transform.childCount > 0)
{
Destroy(this.gameObject.transform.GetChild(0).gameObject);
System.GC.Collect();
}
//}
}
As you can see I am deleting the first child (which I got from asset bundle) then call GC Collect to force garbage collector. but the problem is that my memory is not releasing whenever i unload/destroy the object. Now you will thinking that how i am measuring the memory? I am using WebGLMemoryStats from here. And i am getting this after several iteration of assetbundle load.
Edit: I am using now WebRequest Class to download assetbundle (find here) but still unable to release the memory and sometime get aw snap error.
Even when I am trying to load an empty webgl build again and again its increase the memory heap and then sometime i get aw snap or memory error and chrome crash.
As you can see the initial load is about 1.2 Mb but when i refresh page and take snap shot, it snapshot brings with incremented memory.
The AssetBundles are cached to Unity's Cache folder in the local storage device. The WebPlayer shared cache allows up to 50 MB of cached AssetBundles.
An AssetBundle is content that is stored separately from a main game or application and loaded (or downloaded, in the case of mobile and online apps) at runtime. This helps minimize the impact on network and system resources by allowing customers to download and install only the parts they need.
As a note, you'll never get this to function as perfectly as you may think. There are utilities for cleaning up garbage and unloading assets but even if you follow all best practices, you still might not get Unity to clean up all the garbage (it does a lot in the background that'll retain allocated memory and there's not much you can do about it). If you're curious about why this is, I'd suggest their writeup on Heap Fragmentation as well as their Memory Optimization Guide.
As far as what you're doing with your specific project, there are at least some improvements you can make:
1) Avoid using the WWW
class at all costs. It creates a lot more garbage than it's worth, doesn't always clean up well, and is obsolete in newest versions of Unity. Use UnityWebRequest to download bundles instead.
2) Don't get in the habit of loading a bundle just to load a single asset and then unloading that bundle. If you have lots of loads occurring at runtime, this will cause thrashing and is a fairly inefficient way of managing your bundles. I noticed you're calling bundle.Unload(false)
which means the bundle is being unloaded but the loaded prefab asset isn't. I'd suggest restructuring this in a way that you can:
bundle.Unload(true)
3) Be careful with your call to StopCoroutine(loadBundleRef);
(if loadBundleRef
is a Coroutine
object that is running your web request and bundle loading logic). Interrupting these async operations could lead to memory issues. You should have something in place that ensures web requests and bundle loads either finish completely or, on failure, throw and let your game recover. Don't allow something like StopCoroutine
to interrupt them.
4) System.GC.Collect();
is slow and garbage collection happens periodically anyway. Use it sparingly and you might also want to call Resources.UnloadUnusedAssets
before calling it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With