2

We have our asset bundles stored on an Amazon S3 bucket. When the game starts, it determines which bundles it needs to download new versions of, using WWW.LoadFromCacheOrDownload.

The problem we're running into is the memory iOS reports it has allocated for our app keeps increasing, however the memory Unity reports it's using (through the profiler) always stays the same. We have enough bundles that by the time it has finished downloading everything we need, it has invariably received a memory warning from iOS, and we are shutdown due to memory pressure shortly after.

Common solutions we have in place already: Unloading the assetbundle after the WWW is finished, using assetBundle.unload(), calling Resources.UnloadUnusedAssets(), and calling Dispose() on the WWW. None of it is solving the problem.

Code follows:

    private IEnumerator DownloadBundle(DownloadQueueEntry entry, DownloadFinishedCallback callback)
    {
        while (!entry.finished)
        {
            // grab bundle off S3
            string url = string.Format(BUNDLE_URL_FORMAT, entry.directory, entry.assetName);

            WWW www = WWW.LoadFromCacheOrDownload(url, entry.version);

            yield return www;

            if (string.IsNullOrEmpty(www.error))
            {
                Debug.Log("[BundleDownloader] Download Completed " + entry.assetName);

                entry.finished = true;
                entry.downloading = false;
                www.assetBundle.Unload (true);
                Resources.UnloadUnusedAssets ();
            }
            else
            {
                // usually timed out resolving host, just try again for now
                Debug.LogError("[BundleDownloader] Download failed: " + url + " Error: " + www.error);
            }

            www.Dispose();
            www = null;
        }
        if(callback != null)
        {
            callback ();
        }

    }

--edit--

A screenshot showing the increasing memory usage is at the link below. Memory usage proceeds like that until it has chewed up around 150MB. This is all in an scene that only has a GameObject for init scripts in it (no art or anything).

https://www.dropbox.com/s/3b6skexz6xhug5g/Screenshot%202014-03-28%2014.54.26.png

PaxThor
  • 21
  • 1
  • 3

3 Answers3

1

As the Unity docs suggest, you should really be encapsulating your usage of the WWW object/caching routines in a "using" statement block.

using System;
using UnityEngine;
using System.Collections;

public class CachingLoadExample : MonoBehaviour {
public string BundleURL;
public string AssetName;
public int version;

void Start() {
    StartCoroutine (DownloadAndCache());
}

IEnumerator DownloadAndCache (){
    // 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 (BundleURL, version)){
        yield return www;
        if (www.error != null)
            throw new Exception("WWW download had an error:" + www.error);
        AssetBundle bundle = www.assetBundle;
        if (AssetName == "")
            Instantiate(bundle.mainAsset);
        else
            Instantiate(bundle.Load(AssetName));
                // Unload the AssetBundles compressed contents to conserve memory
                bundle.Unload(false);

    } // memory is freed from the web stream (www.Dispose() gets called implicitly)
}
}

"using" statements are a C# feature to ensure that "Dispose()" methods work correctly (and in many cases, are called automagically for you).

As stated in MS's docs: http://msdn.microsoft.com/en-us/library/yh598w02.aspx

"[using] Provides a convenient syntax that ensures the correct use of IDisposable objects."

I'm guess your memory leak is due to these functions not performing as intended (possibly due to improper configuration, not sure).

  • Will try. I don't know if it the same issue, but the second time I try loading the same texture from the web it loads instantaneously, meaning it was stored somewhere. – Cristian Garcia Aug 04 '14 at 01:13
1

I had similar issues on AssetBundle downloading on iPad. However, in my case;

  • I was downloading assetbundle from server (without using cache) and loading it later. In one asset bundle, it boosts the memory if the asset bundle has images more than 100 or lets say 200.
  • This was not UnityDestroyWWWConnection or "using" issue. I was downloading 60MB asset bundle (with using best-compression on asset bundle generation) and it uses about 450MB while downloading.
  • I checked the result from instrument and saw tons of small malloc while downloading asset bundle. You can check the instrument screenshot from here.

My guess - not sure: Unity extract the information from asset bundle while downloading continues, which gives error on memory. It gets the header info first, and understands that it is unity3d object and because it downloads with www class it prepare for WWW asset bundle.

My solution was:

  • Compressing assetbundle and putting server as zip.
  • Downloading asset bundle zip and extracting on iPad (using SharpZipLib)
Dogukan
  • 111
  • 2
0

We ran into a similar issue in our app. We were loading lots of textures from WWW and noticing iOS being the only platform to have a memory leak from it. We eventually found our solution here http://forum.unity3d.com/threads/www-memory-leak-ios.227753/. Basically, there is a known issue in unity 4.3 that leaks the data from www calls. This SHOULD be fixed in unity 4.5. In the meantime, you can follow Alexey's suggestion to modify the code in the generate xcode project or update to 4.5:

4.5 will have the fix. Essentially you need: search for extern "C" void UnityDestroyWWWConnection(void* connection) in WWWConnection.mm

[delegate.connection cancel]; 
delegate.connection = nil;
[delegate.data release]; // <-- ADD THIS
[delegate release];
tboling1
  • 488
  • 4
  • 13