Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

References bound to a Scene Context stay in memory after scene change #654

Open
Racso opened this issue Aug 15, 2019 · 11 comments
Open

References bound to a Scene Context stay in memory after scene change #654

Racso opened this issue Aug 15, 2019 · 11 comments

Comments

@Racso
Copy link

Racso commented Aug 15, 2019

Hello!

I've found that Zenject somehow is "leaking" assets in memory. What I mean by this is that assets that are bound to a Scene Context are kept in memory even when the Scene has been changed. I have the theory that some static reference is keeping those assets from being collected by the GC, but that's all I got; I couldn't pinpoint the exact cause of the problem.

Any help to solve this issue (or find a workaround for it) would be appreciated!

Setup to reproduce:

  • An empty Scene A.
  • A Scene B with a Scene Context, a MonoInstaller and a GameObject with a Component of type TestInjectableComponent. The TestInjectableComponent should have some references to some assets, such as Sprites (e.g. a List<Sprite>). The MonoInstaller binds class TestInjectableComponent to that instance.
  • A Scene C that only has the GameObject with a TestInjectableComponent (with the references to the assets). No Zenject-related components should exist here.

Steps to reproduce:
Note: to verify Assets in memory, use Unity's profiler to take a Memory Snapshot.

  • Start in Scene A. Check that no Sprites are loaded into memory.
  • Load Scene C (No Zenject). Check that the Sprites referenced by TestInjectableComponent are loaded into memory.
  • Load Scene A. Check that no Sprites are loaded into memory.
  • Load Scene B (Zenject). Check that the Sprites referenced by TestInjectableComponent are loaded into memory.
  • Load Scene A. No sprites should be loaded in memory at this point. However, you'll find that the sprites are still there.

Sample Project
I've attached a test project where you can verify this behavior. Use the keyboard to change to the desired scene: S for the "Starting Scene", N for the "No-Zenject Scene" and Z for the "Zenject Scene".

Zenject Leak Test.zip

@Racso Racso changed the title Injected GameObject stays in memory after scene change References bound to a Scene Context stay in memory after scene change Aug 15, 2019
@wirde
Copy link

wirde commented Dec 12, 2019

Did you find any solution/workaround for this? I also have leaks in my project which I believe could be related to this behavior.

@koldkane
Copy link

I find ZEN_INTERNAL_NO_POOLS define word can fix the issue in the sample project.

@koldkane
Copy link

Here is the fix:

modesttree#64

@sapiscow
Copy link

sapiscow commented Jul 7, 2021

Hello, i've found the same issue as here, have anyone find the solution?

@Racso
Copy link
Author

Racso commented Jul 7, 2021

@sapiscow Have you tried using Zenject's current project? This version is obsolete and hasn't been updated in quite a bit. Check https://github.com/modesttree/Zenject for the current version.

@sapiscow
Copy link

sapiscow commented Jul 7, 2021

Yes, i've tried the latest version (Extenject 9.2.0) in Unity 2020 LTS, did you solve your problem with only update the Zenject? or
Is Unity 2020 not supported yet?

@Racso
Copy link
Author

Racso commented Jul 7, 2021

@sapiscow Not really. We made a workaround ourselves as Zenject wasn't being updated at that time (and we didn't know about Extenject).

It's been a while, and I no longer have easy access to that git history to verify for sure what we did (we tried a lot of stuff). However, I suspect that the key of the fix was adding this in SceneContext.cs:

private void OnDestroy()
{
    _container.UnbindAll();
}

Give it a try.

@sapiscow
Copy link

sapiscow commented Jul 7, 2021

@Racso After i add that code in SceneContext.cs, the GameInstaller (an installer script that also in the same gameobject as SceneContext) is cleared from memory after the scene unloaded, but the others is still have issue

@Racso
Copy link
Author

Racso commented Jul 7, 2021

@sapiscow OK, last shot I can give you:

In your installers (e.g. your GameInstaller), add code in OnDestroy to nullify any references you have. Basically, do this:

private void OnDestroy()
{
  referencedObject1 = null;
  referencedObject2 = null;
  referencedObject3 = null;
}

Where rerencedObject1, referencedObject2 and referencedObject3 are objects (e.g. MonoBehaviours) that you referenced in the installer.

For example: if you had this in the installer:

[SerializeField] private MyGameInput input;

You would add this in OnDestroy:

input = null;

@Racso
Copy link
Author

Racso commented Jul 7, 2021

That being said, I suspect you have other kind of issue. My last suggestion probably won't make a difference because if your GameInstaller is being unloaded correctly (as you mentioned), it won't keep references alive in memory (therefore, nullifying the pointers is useless).

Maybe you have statics in your code, or something similar?

@sapiscow
Copy link

sapiscow commented Jul 7, 2021

@Racso the GameInstaller doesn't have any reference to another, it just contains Bind functions for any interface that used in the scene.

And now, i've tried the sample project from Zenject, there are two sample projects, one that simple and one advance.
For the simple project, there are no leak issue,
But when i tried the advanced sample, there are same leak issue there
I've post the issue here modesttree#246
I hope Zenject Developer is trying to fix this

Thank you btw @Racso for your help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants