My game is almost all procedural, mostly runtime generated, and running pretty much in just one scene.
I read that most of the time, unusedassets are dumped with every scene change.
So should I Resources.UnloadUnusedAssets() for most scripts that are basically one time use (such as scripts for customization screens), since I never change scenes, for any script that has OnEnable or Start()?
I use OnEnable a lot, and that often brings in in references, lots of customization things like materials, textures, etc…
Also, loading small scenes is pretty fast. You could consider using additional scene loading/unloading. I often do it for dialogs or things that are rarely needed and are small (in size and logic). UnloadUnusedAssets() is quite a brutal method of handling memory imo. I’d only use it as a last resort.
Today (almost a year later) I had a problem switching my units on and off, when there were hundreds of them (to switch between overland and area maps). I got massive GCMarkDependency problems when swapping (in same scene, just turning off a bunch of stuff and turning on a bunch of stuff).
It was odd, because I could spawn 100 units in a second, but to turn them off, and turn them back on took almost half a minute each way. Yet 20,000 trees could turn on and off in a snap.
When I made this thread, I thought Resources.UnloadUnusedAssets() would help with GC. (which I later found, because of profile graph colors being so similar, GC was never an issue with my game any way, it was actually “other”)
Turns out, Resources.UnloadUnusedAssets() was the cause of the massive GCMarkDependency problem!
Thankfully this poster discovered the cause. Who knows how long I would have torn my hair out over this without this answer, and it probably would have been one of the last things I tried.
Yeah, you shouldn’t call Resources.UnloadUnusedAssets all over the place but only in a rather controlled way. E.g. once after a destructive SceneUnload (i.e. this inncludes a Scene Load that replaces the previous scene) if you need to lower the memory pressure at the beginning of that scene, and in particular if you’ve created a bunch of instances of types inheriting from UnityEngine.Object at runtime and lost track of them (and therefore can’t call Destroy on them to get rid of them). Similar logic applies to for procedural level creation workflows where you have to either track everything you created and loaded so you can directly Destroy or unload them, or find a loading screen or similar situation within which you could trigger Resources.UnloadUnusedAssets.
Addressables and AssetBundles in general can help with the loading part, prefabs can help you in the creation part. Where Prefabs also helps in reducing the amount of Managed Shell objects to all these UnityEngine.Objects you’re creating at runtime. Every such objectthat you access via scripting code gets a shell for scripting access. So when you create everything from Scripting code, that’s all of them. If part of these objects is loaded from prefabs or scenes, onlytrh objects you actually need to access during runtime get Managed Shell Objects created for them.
Lastly, GC.MarkDependencies is the marker for the Asset GC, i.e. UnloadUnusedObjects. The Asset GC triggers the Scripting GC as part of the MarDependencies step, but the Scripting GC (GC.Collect) is otherwise separate from this.
This doesmean though that the time the Asset GC take, while (partially) multithreadded, scales linearly with the amount of Managed (aka Scripting) Objects (including the Managed Shells for Native Objects) and Native (aka Assets and Scene Objects) Objects AND with the amount of connections between these.
I hope this clarifies some things about this rather abstract profiler marker
Glad you said something, because I checked and sure enough, was getting memory leaks.
So… disabling game object while meaning to enable them again in the future, do not use UnloadUnusedAssets()
but, disabling gameobject that creates a new mesh/generated object when enabled, use it.
In that case, it sounds like you should either not recreate the mesh on a second OnEnable, or Destroy the mesh in OnDisable. If you create an Asset Type object at runtime, you’re in charge of its lifetime.
I don’t use enable, start or awake for much of anything anymore. That was almost a year ago. I don’t trust them. I use My own Initialize() and Activate() and Refresh() instead so I have complete control of the data streams / execution order.
Oh wow, look at that, you can just Destroy(meshInstance); I have never considered destroying anything besides GameObjects. Whelp, in that case, I’m gonna go through and Destroy the meshInstances I have to generate to get around SkinnedMeshRenderers and all their shared stuff, because I do not like Resources.UnloadUnusedAssets().