Author Topic: Atlas leaking when loaded from scene in asset bundles?  (Read 17927 times)

boudinov

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 10
    • View Profile
Atlas leaking when loaded from scene in asset bundles?
« on: February 26, 2015, 08:55:52 AM »
Hello,
Using memory profiler, attached to standalone Windows player, we see our main Atlas texture leaking every time we switch scenes. I have a feeling, the way we use them with asset bundles is the cause, but not sure.

The scenario is not that usual:
For the UI, we have 3 asset bundles containing several scenes with NGUI stuff in them - one bundle for each main state of the game - Login, Garage, Battle.
When game state changes, we load new 3D world using Application.LoadLevel, which cleans old gameobjects(UI stuff too) and does implicitly Resources.UnloadUnusedAssets. Then we load the UI scenes from the corresponding bundle, using LoadLevelAdditive, then we unload the bundle.

So you can imagine, the main atlas that is leaking, is present in each of these bundles (we are building them using BuildPipeline.PushAssetDependencies)

We already fixed couple of places that hold static references to NGui stuff, which we found using the profiler, but the atlas is still leaking - new instance appearing after each switch of game state.

For the leaked atlas texture, profiler now shows just 2 items in (Referenced By:) section:
UIAtlas
ManagedStaticReference

Drilling down these items shows nothing.

I managed to clean these leaked instances crudely by doing this after scene switch:
  1.                 foreach(var atlas in Resources.FindObjectsOfTypeAll<UIAtlas>())
  2.                         {
  3.                                 Texture tex = atlas.texture;
  4.                                 GameObject.Destroy(atlas.spriteMaterial);
  5.                                 GameObject.Destroy(atlas);
  6.                                 GameObject.Destroy(tex);
  7.                         }

Any idea what could be causing this?

Thanks!
« Last Edit: February 26, 2015, 09:05:55 AM by boudinov »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Atlas leaking when loaded from scene in asset bundles?
« Reply #1 on: February 27, 2015, 04:45:57 AM »
Destroying a texture doesn't release it from memory. You need to use UnloadUnusedAssets: http://docs.unity3d.com/ScriptReference/Resources.UnloadUnusedAssets.html

You also need to do this after all NGUI draw calls were destroyed. Disable the UI, call NGUITools.ImmediatelyUpdateDrawCalls. Alternative is to destroy the UI then yield until next frame, then do your destroying of material, atlas, texture and UnloadUnusedAssets.

FrankYan

  • Newbie
  • *
  • Thank You
  • -Given: 6
  • -Receive: 2
  • Posts: 18
    • View Profile
Re: Atlas leaking when loaded from scene in asset bundles?
« Reply #2 on: February 28, 2015, 02:56:36 AM »
Can you Give some code to express the process of unload unused atlas.
Thanks.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Atlas leaking when loaded from scene in asset bundles?
« Reply #3 on: March 01, 2015, 04:57:16 PM »
  1. using UnityEngine;
  2.  
  3. public class DestroyMyAtlas : MonoBehaviour
  4. {
  5.     public UIAtlas atlas;
  6.  
  7.     public void DestroyNow ()
  8.     {
  9.         UIRoot.list[0].gameObject.SetActive(false);
  10.         UIDrawCall.ClearAll();
  11.         Object.Destroy(atlas.texture);
  12.         Object.Destroy(atlas);
  13.         atlas = null;
  14.         Resources.UnloadUnusedAssets();
  15.     }
  16. }

jenemia

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 7
    • View Profile
Re: Atlas leaking when loaded from scene in asset bundles?
« Reply #4 on: March 20, 2015, 01:32:13 AM »
Hi,
I'm same problem.

I write like this code.

  1. foreach(UISprite sprite in gameObject.GetComponentsInChildren<UISprite>())
  2. {
  3.     if( sprite != null )
  4.         sprite.atlas = null;
  5. }
  6. GameObject.Destory(gameObject);
  7.  
  8. yield return null;
  9.  
  10. Resources.UnloadUnusedAssets();
  11.  

Nobody not referenced a UIAltas. Because, all gameObject is destoryed.
But, I can see the only one "referenced by",  that in Unity memory profile with detail "Take Sample Eiditor" , self "UIAtals".
So, i see memeory leak while change the scene.
Scene be made up other each UIAtals.


And,
I see UIAtlas that I never create, never load gameObject in scene.

did i do something wrong?
« Last Edit: March 20, 2015, 01:43:56 AM by jenemia »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Atlas leaking when loaded from scene in asset bundles?
« Reply #5 on: March 21, 2015, 09:32:29 PM »
All destroy calls are always delayed in Unity. You need to wait for one frame.

jenemia

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 7
    • View Profile
Re: Atlas leaking when loaded from scene in asset bundles?
« Reply #6 on: March 23, 2015, 09:54:53 PM »
I destroy all GameObjects that use atlas and wait one frame.
(yield return null or yield return new WaitForEndFrame)
next call "Resource.UnloadUnusedAssets()" , "System.GC.Collect()" and "System.GC.WaitForPendingFinalizers()".

but,
I see the memory profile with detailed with "Take Sample : Eidtor."
There is a .png file that located Assets/Texutre2D.
and it is pointed a material in "Referenced By:".
.png and material are made up a atlas prefab.
only one material, nothing gameObject.



if i allocate null at atlas when destroy gameObject , i don't see atlas when i create prefab for back to scene.
« Last Edit: March 23, 2015, 11:20:11 PM by jenemia »

Rajken

  • Newbie
  • *
  • Thank You
  • -Given: 1
  • -Receive: 2
  • Posts: 12
    • View Profile
Re: Atlas leaking when loaded from scene in asset bundles?
« Reply #7 on: March 24, 2015, 08:54:29 AM »
One thing that you could try is to create an standalone build and then profile that one.
Because when you do it in the editor unity can some time load in the atlas that the editor needs and when you take an sample in the editor you get both your game and the editors ref count

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Atlas leaking when loaded from scene in asset bundles?
« Reply #8 on: March 24, 2015, 10:43:08 AM »
You should also call UIDrawCall.ReleaseInactive().

jenemia

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 7
    • View Profile
Re: Atlas leaking when loaded from scene in asset bundles?
« Reply #9 on: March 25, 2015, 03:35:30 AM »
no.. remain material of atlas.

my memory managed sequence is
1. destory gameObject contained uisprite
2. yield return null;
3. UIDrawCall.ReleaseInactive;
4. yield return null;
5. Resources.UnloadUnusedAssets
6. yield return null;
7. System.GC.Collect
8. System.GC.WaitForPendingFinalizers

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Atlas leaking when loaded from scene in asset bundles?
« Reply #10 on: March 25, 2015, 12:11:55 PM »
The atlas, once loaded, will remain in memory. If you want to get rid of it, then you need to explicitly destroy the atlas's texture, followed by the atlas itself. Your original posts suggested you doing it, but the latest post doesn't show this.

1. Destroy the game object containing the sprite.
2. Destroy the material and texture of the atlas that was used by #1.
3. Destroy the atlas.
4. yield return null;
5. UIDrawCall.ReleaseInactive.
6. Resources.UnloadUnusedAssets.

always_beta

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 1
    • View Profile
Re: Atlas leaking when loaded from scene in asset bundles?
« Reply #11 on: May 06, 2015, 09:08:20 PM »
The atlas, once loaded, will remain in memory. If you want to get rid of it, then you need to explicitly destroy the atlas's texture, followed by the atlas itself. Your original posts suggested you doing it, but the latest post doesn't show this.

1. Destroy the game object containing the sprite.
2. Destroy the material and texture of the atlas that was used by #1.
3. Destroy the atlas.
4. yield return null;
5. UIDrawCall.ReleaseInactive.
6. Resources.UnloadUnusedAssets.

Whenever I'm sure atlas A is not being used at the moment, I used following solution to release the texture and material of atlas A from memory:
  1. UIAtlas[] atlases = Resources.FindObjectsOfTypeAll<UIAtlas>();
  2. foreach (var atlas in atlases)
  3. {
  4.     if (atlas.name == "TargetAtlasName")
  5.     {
  6.         Resources.UnloadAsset(atlas.texture);
  7.         Resources.UnloadAsset(atlas.spriteMaterial);
  8.         break;
  9.     }
  10. }
  11.  

From my test, the texture and material can be released from memory safely and sprites can also be rendered correctly next time when needs to show.
Does this solution have any side effects on any aspect?

I'm using NGUI v3.6.8.

« Last Edit: May 07, 2015, 03:04:11 AM by always_beta »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Atlas leaking when loaded from scene in asset bundles?
« Reply #12 on: May 07, 2015, 09:21:11 PM »
Resources.FindObjectsOfTypeAll is going to be very slow, but aside from that it's fine.