Search Unity

iOS "AssetBundle Load and Unload" makes memory accumulation only recent Unity Version

Discussion in 'iOS and tvOS' started by Gohn, May 2, 2014.

  1. Gohn

    Gohn

    Joined:
    May 2, 2014
    Posts:
    1
    My game repetitively loads and unloads lots of assetbundles when scene changes.

    In Unity 4.3.4, roughly 10mb memory is increased when I compare the one before with the other after.

    The problem is the memory does not decrease, although I release GameObject, mesh and www with dispose().

    Garbage Collector is running well too.

    So, my game starts with 100mb memory, but it ends with 500mb and killed by xcode.


    I did not understand why it makes problem, so I tried it on Unity 4.1.5 version.

    Surprisingly, it does not increase memory and release everything very well.



    Is there any one who had same trouble like me or solve this issue?

    ( only in iOS. Android works well)
     
    Last edited: May 7, 2014
  2. dackattack

    dackattack

    Joined:
    Dec 18, 2013
    Posts:
    4
    I am seeing this as well. When using WWW to load an AssetBundle, Unity leaks the size of the compressed AssetBundle it loads. This happens every time it loads a bundle, even if it had loaded the bundle previous.

    I have filed a bug with Unity (Case 605863) and hope to hear back soon, in the meantime I am looking for a workaround. You can load the bundle via memory and not run into this issue, but if you want to use Unity's caching then you have to use WWW.
     
  3. Alexey

    Alexey

    Unity Technologies

    Joined:
    May 10, 2010
    Posts:
    1,624
    i will check case on monday but for now: yes we found WWW leaking way after releasing 4.3.4 into the wild. You can fix it yourself (it is trampoline specific code) though usual warning applies - backup, test, and then test again
    in trampoline you need Classes/Unity/WWWConnection.mm

    search function "extern "C" void UnityDestroyWWWConnection(void* connection)"
    it will look like this:

    Code (csharp):
    1. extern "C" void UnityDestroyWWWConnection(void* connection)
    2. {
    3.     UnityWWWConnectionDelegate* delegate = (UnityWWWConnectionDelegate*)connection;
    4.  
    5.     [delegate.connection cancel];
    6.     delegate.connection = nil;
    7.     [delegate release];
    8. }
    9.  
    change it to

    Code (csharp):
    1. extern "C" void UnityDestroyWWWConnection(void* connection)
    2. {
    3.     UnityWWWConnectionDelegate* delegate = (UnityWWWConnectionDelegate*)connection;
    4.  
    5.     [delegate cleanup];
    6.     [delegate release];
    7. }
    8.  
    now you need to add the cleanup method
    to minimize issues with next update (4.5 have it fixed sure)
    search for "- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response"

    and *right before* it add

    Code (csharp):
    1.  
    2. - (void)cleanup
    3. {
    4.     [_connection cancel];
    5.     _connection = nil;
    6.  
    7.     [_data release];
    8.     _data = nil;
    9. }
    10.  
    so it will look like this in the end:

    Code (csharp):
    1. - (void)cleanup
    2. {
    3.     [_connection cancel];
    4.     _connection = nil;
    5.  
    6.     [_data release];
    7.     _data = nil;
    8. }
    9.  
    10.  
    11. - (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
    12. {
    13.  
    i hope that makes sense 8)
    P.S. sure i'll check the reported bug for possible extra stuff
     
    Last edited: May 3, 2014
  4. Ash-Tang

    Ash-Tang

    Joined:
    Feb 20, 2013
    Posts:
    1
    This solution is very helpful, I slove my memery leak in ios device problem, thank you very much!
     
  5. jnikolai

    jnikolai

    Joined:
    Jan 22, 2014
    Posts:
    2
    I'm seeing something similar, though not specifically on iOS -- I'm leaking on android as well.

    It seems to be related to the 'unloadAllLoadedObjects' flag of unload:
    Unload(true) works fine -- Unload(false) is leaving around 1 copy of everything in the bundle (shaders/textures/meshes, and VBOs) for every call. I have a simple test case (just loading/unloading the same asset bundle once per second), and it's going up consistently and eventually crashing, on all devices I've tried. And it happens even if I never instantiate or touch any assets from the bundle... And just for fun, I tried calling Destroy on the mainAsset from the bundle, but get the same result.

    Here's the test case:

    Code (csharp):
    1.  
    2. public class AssetBundleTest : MonoBehaviour {
    3.  
    4.     private DateTime nextTime = DateTime.UtcNow;
    5.  
    6.     void Start() {
    7.     }
    8.    
    9.     void Update() {
    10.         if( nextTime > DateTime.UtcNow )
    11.             return;
    12.  
    13.         nextTime = DateTime.UtcNow + TimeSpan.FromSeconds(1);
    14.         StartCoroutine(Crashity());
    15.     }
    16.  
    17.     public IEnumerator Crashity()
    18.     {
    19.         string url = "http://path/to/something.unity3d";
    20.         WWW assetWWW = WWW.LoadFromCacheOrDownload(url, 1);
    21.         yield return assetWWW;
    22.  
    23.         assetWWW.assetBundle.Unload(false); // NOTE: 'true' will work here
    24.         assetWWW.Dispose();
    25.     }
    26. }
    27.  
    All our code is set up to load an asset bundle, instantiate assets out of it, and immediately unload it -- so we're depending on the Unload(false) path. If we can't depend on this I'll look into refactoring to keep the bundle around and unload it when the assets are destroyed... but I'm hoping to figure out a way to make it work as-is.

    And, this also seems to be specific to newer unity versions -- the same code on 4.2 didn't have this problem.

    Thanks!
     
    Last edited: May 7, 2014
  6. jnikolai

    jnikolai

    Joined:
    Jan 22, 2014
    Posts:
    2
    I did find a temporary workaround: calling 'Resources.UnloadUnusedAssets' after the AssetBundle.Unload call will free the extra allocations. I'm worried that this might be a performance bottleneck in the long run, but it works for now.
     
    kayy likes this.
  7. Nabren

    Nabren

    Joined:
    Mar 7, 2014
    Posts:
    61
    I know this is from 2014, but we are running into something similar with Unity 2018.1.8 using
    UnityWebRequestAssetBundle.GetAssetBundle. We are basically downloading thousands of bundles without instantiating any assets at all and it appears to still leak memory on iOS. This was made worse by LZMA compression.

    If I call Resources.UnloadedUnusedAssets with any kind of frequency memory is cleaned up properly. If I don't, memory constantly climbs until we crash. I will update if I find out a better workaround than manually triggering GC constantly.