• Editor
  • Insane amount of garbage collection

  • Modifié
Related Discussions
...
  • Modifié

We've loaded a Unity scene with LOTS of BIG skeleton animation, and the performance is droping significantly. When I deactivate these skeleton animations, everything go much smoother so I am sure that it is coming from them.
I took a look at the profiler and I saw this insane amount of garbage collection:

Image supprimée en raison de l'absence de support de HTTPS. | Afficher quand même

This is not a normal behaviour right ?

Oh and I probably don't have the latest Unity runtime version. My Unity runtime is probably 2 month old

I have a hunch about something fixable.
Are you switching animations or calling SetAnimation or AddAnimation a lot?
What else is your test scene doing?

Around how many is LOTS?

(Make sure you update both Spine-C# and Spine-Unity)

I'm not switching animation during runtime, I just set them at the begining and let them loop.
The scene is basically doing nothing crazy: I can move my player around, I know it takes some CPU because of the collisions et al but on other scenes when there is not much SkeletonAnimation, it runs smoothly.

I have this big SkeletonAnimation which when I disable it, everything goes smoother:

Image supprimée en raison de l'absence de support de HTTPS. | Afficher quand même

The skeleton data depends on 18 png textures which are 2048x2048. However we can see that they are loaded much more than that in the mesh_renderer (it contains 27 materials... why do he need to have many times the same material ?)

I also have a camera who is following the player, and the hiccups are more violent when the big object appear or disappear of the field of view...

The other main source of Skeleton animation is my background, which is probably composed of arround 20 SkeletonAnimation, each having at most three textures of 2048x2048.
If I disable my background, there are no hiccups anymore (even with the big object).

The big question is why these SkeletonAnimations is soliciting the Garbage Collector that much

I would think the number of materials would cause the draw calls to skyrocket.
I think the same material appearing multiple times is from when you stagger the draw order of images coming from different atlases.

Like when the atlas sources in the draw order goes 1, 2, 4, 2, 1, 2, 3, 1. That would be ultimately slower than 1, 1, 1, 2, 2, 2, 3, 4. So even if you only have 4 atlases, it can end up having several materials in the mesh renderer and more draw calls, which can slow your game down if you have enough of those complicated skeletons.
This is true for pretty much any game engine and framework nowadays, not just Spine or Unity.

Are you separating these large textures into different atlases so you can mix and match from a large collection parts?

I can't imagine where the GC problem is coming from though. I don't have Unity Pro myself.
The only potential GC thing I see is AnimationState making and orphaning TrackEntry objects every time you switch an animation. If you're not switching animations a lot, this shouldn't be a problem at all.

Let's see what Nate or other users have to say.

Can you identify where the allocations occur? What hardware are you running on where you see hiccups?

SkeletonComponent minimizes allocations it needs in many ways. The number of vertices it draws can vary as attachments are hidden or shown. Unity requires the vertices array to be the exact size equal to number of vertices drawn. It would be better it Unity allowed us to specify an offset and count to use from the vertices array, but that isn't the case. So, to avoid allocating a new vertices array when the one we have is too large, SkeletonComponent zeros out any extra vertices so they become degenerate.

When drawing from multiple textures, SkeletonComponent needs to provide Unity with a number of "submeshes" (a list of triangle indices, which are indices into the vertices array). Like the vertices array, Unity requires each submesh to be the exact size. Unfortunately in this situation we can only allow the last submesh to be larger than required. We reuse submeshes we have created previously, but if they are the wrong size and not the last one, then we have to allocate a new one that is the right size. I'm afraid this is a Unity limitation. 🙁

That should only affect you if your animations are changing what attachments are visible and the new attachments cause the size of a submesh to change (ie a texture change occurs at a different index).

SkeletonComponent needs a material every time there is a texture change. Eg, if it needs to draw torso, arms, head and the head is on a different atlas page, there will be 2 materials. Texture changes should be minimized, as they hurt performance, especially on mobile. On the desktop the texture changes don't matter so much, and neither should the GC. To reduce texture changes, pack images into a single page or organize your images so fewer texture changes occur. Spine's texture packer uses subdirectories to determine images that should be on the same page. See here:
https://github.com/libgdx/libgdx/wiki/Texture-packer

I don't know where the allocations may occur. My CPU is: Intel(R) Core(TM) i3 CPU m350 2.27GHz, and i'm using Windows 7

So basically, the only way to enhance the performances is to have less mesh loaded in the renderer?
Sometimes it's unavoidable to use 2 different materials, but sometimes, SkeletonData load meshes in the renderer that way: A,B,A,B (4 meshes instead of 2).
I believe it has something to do with the drawing order right ? The cause would be that I probably draw a part from the texture A, then on top, one from the texture B, then on top again from texture A, then on top again from texture B.
To solve this, I would have to make sure I don't sandwich a texture A with texture B on the bottom and on the top (which would ultimately have texture B to be stored on the renderer twice)

Am I missing something ?

Leoss a écrit

To solve this, I would have to make sure I don't sandwich a texture A with texture B on the bottom and on the top (which would ultimately have texture B to be stored on the renderer twice)

You got it. The renderer has a list of materials, each one represents a texture change. The texture isn't actually stored twice.

Leoss a écrit

So basically, the only way to enhance the performances is to have less mesh loaded in the renderer?

I don't know, because we don't know where the allocations occur. Can you debug it further?

We reduced the number of mesh stored on the renderer using your tips and it actually improved the performance a lot !
Thanks Nate

Cool! Then likely it was the texture changes hurting you. On mobile you can only have maybe 20-30, on desktop you don't have to worry so much but I guess you are really going nuts with things. :nerd: