Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Skinned Mesh Material leak?

Discussion in 'Addressables' started by KB73, Jul 29, 2020.

  1. KB73

    KB73

    Joined:
    Feb 7, 2013
    Posts:
    234
    I'm not sure if this is a bug with the way we're dealing with addressables or something more fundamental.

    We're on 2019.4.5 Unity and the latest addressables

    We load a prefab that contains a skinned mesh and one material assigned to the mesh.

    AsyncOperationHandle<GameObject> task = Addressables.LoadAssetAsync<GameObject>( // resourceLocation Object);

    await task.Task

    GameObject go = GameObject.Instantiate(task.Result);

    .. Wait a bit

    GameObject.Destroy(go);
    Resources.UnloadUnusedAssets();
    GC.Collect();

    We are always left with the object in memory on device and editor.

    If we remove the material in the skinned mesh, the object is cleaned up as expected.

    The material is not part of the bundle nor is it tagged as an addressable but is pulled in via reference i would assume when the bundle is built.

    Is this expected? Is this a bug? Any proposed workarounds?

    thanks
     
    Last edited: Jul 29, 2020
  2. ProtoTerminator

    ProtoTerminator

    Joined:
    Nov 19, 2013
    Posts:
    566
    You need to call
    Addressables.Release(task)
    .
     
  3. KB73

    KB73

    Joined:
    Feb 7, 2013
    Posts:
    234
    Unfortunately i have tried all those solns and usually run into this:

    Addressables.Release was called on an object that Addressables was not previously aware of. Thus nothing is being released

    I also tried the Addressables.InstantiateAsync with the Release above and still no luck

    Release/ReleaseInstance afaik should only be used if relying on Addressables ref counting which we are not right now.
     
  4. ProtoTerminator

    ProtoTerminator

    Joined:
    Nov 19, 2013
    Posts:
    566
    Since you are using the
    LoadAssetAsync
    api, you need to hold onto the
    AsyncOperationHandle
    instance so that you can pass it into the
    Release
    api. If you just use
    InstantiateAsync
    , then you should use
    ReleaseInstance
    instead of
    Destroy
    , and you won't need to hold onto the handle.
     
  5. KB73

    KB73

    Joined:
    Feb 7, 2013
    Posts:
    234
    Correct, i get that but i am not seeing any different behaviour, i have tried all variants.
    I am going to just pull out the code into a small project and test it with an asset in isolation as a sanity check. If it is still occurring, i'll follow up.

    thnx
     
  6. KB73

    KB73

    Joined:
    Feb 7, 2013
    Posts:
    234
    Hmm so yes, my test project is working fine with the above code, will have to do more investigation in the main project, thnx for confirming clean up code
     
  7. KB73

    KB73

    Joined:
    Feb 7, 2013
    Posts:
    234
    Ok so i have everything working as discussed, the issue comes to LoadAssetsAsync ( note: s )....
    This will only return back 1 AsyncOperationHandle
    We use the LoadAssetsAsync to rapidly load in a folder of assets but we use the assets at various times. Unfortunately there is no way i can see to get a per AsyncOperationHandle per asset via this api so i can release individual assets?

    The documentation states that you can release on the Result but again, for the entire handle this is fine but i don't want to release all 100 objects, only a subset

    If i revert back to LoadAssetAsync, it works, but it is about 10x slower to load in

    What's the expected behaviour to release assets independently when loaded via LoadAssetsAsync or is that not possible?

    If not then is the expectation that i manually filter out what should be loaded / unloaded via this call and release in one go?

    thnx
     
  8. ProtoTerminator

    ProtoTerminator

    Joined:
    Nov 19, 2013
    Posts:
    566
    What does your code look like to load them individually? It shouldn't be that much slower.

    I'm honestly not sure. If what you say is true about passing handle.Result to Release, then I would assume that you can pass each loaded object into Release.
     
  9. KB73

    KB73

    Joined:
    Feb 7, 2013
    Posts:
    234
    This is the single LoadAsset way

    foreach (var key in resourceKeys)
    {
    AsyncOperationHandle<Object> handle =
    Addressables.LoadAssetAsync<Object>(locDb[key]);
    await handle.Task;
    }

    vs

    await Addressables.LoadAssetsAsync<UnityEngine.Object>(locDB, result => { // do somethin // ).Task;

    I assume it's just the fact it has to do more work per asset load vs some optimized path via LoadAssets

    Unfortunately LoadAssetsAsync i don't get an asyncHandle per object which i understand, so i have to group them together in a way to clean up the release later...
     
  10. ProtoTerminator

    ProtoTerminator

    Joined:
    Nov 19, 2013
    Posts:
    566
    Well there's your problem. You are waiting for each one to complete before starting the next. Change it to this and it should be fast:


    Code (CSharp):
    1. var tasks = new List<Task<Object>>();
    2. foreach (var key in resourceKeys)
    3. {
    4.     AsyncOperationHandle<Object> handle =
    5. Addressables.LoadAssetAsync<Object>(locDb[key]);
    6.     tasks.Add(handle.Task);
    7. }
    8. await Task.WhenAll(tasks);
    This starts all operations running in parallel, then uses Task.WhenAll to wait for all of them to complete.
     
    KB73 likes this.
  11. KB73

    KB73

    Joined:
    Feb 7, 2013
    Posts:
    234
    doh, thanks for the catch