Please Help - Instantiate Spine Prefab +220 Megs to Memory
I updated my spine runtime and when I got to testing on device about a week and a half ago I found a huge memory increase. Today I pinned it down to Spine.
I am currently at 3.2.01 using the 3.1 runtime with the 3.2 beta on top. I did this after I updated to 3.1 to see if I could improve the issue. Please Help! This is holding up my project and my clients are getting nervous I may not hit my finish date.
That's not much to go on.
Was that large memory footprint always there or you just saw it because that was the first time you tested?
Can you describe your setup?
What's in your prefab?
What's your skeleton like?
How many textures do you have for that skeleton? What are their dimensions?
Are you using json or binary?
What is the code that spawns it?
Does it make a difference when you instantiate one or instantiate several?
What's your Unity version? Have you tried an older or more recent version?
The large memory footprint was NOT there before.
Using Unity 5.3.4p6.
My prefab has the Skeleton Animation and a bunch of stuff. I created a new prefab with SkeletonAnimation and tested with the same results.
There is one large 1024x1024 texture. Power of two, squared.
Using Json.
public void CreateTestMoiku() {
GameObject ob = Instantiate(testMoikuPrefab) as GameObject;
ob.name = testMoikuPrefab.name;
}
That's it and I my memory in Xcode goes from 280 to 514 ish.
I can try creating several of them. But something is off and the moment I noticed this was when I updated my spine runtime.
I appreciate your questions and help with this. Thanks!
EDIT: Creating more DOES NOT incur more memory. Just creating a simple spine SkeletonAnimation prefab makes memory explode by 220 megs.
SkeletonAnimation rules out the old Unity Animator bug (from what I've read, it's kind of similar. A large memory allocation spike).
No difference with multiple instantiation could mean it's something that happens at loadtime.
JSON means if it's not a texture thing (makes no sense), we can check the SkeletonJson loader.
iOS means it's possibly an interaction with IL2CPP. (This has been causing a lot of problems, not just with Spine)
Does it only happen with that specific skeleton or any? Have you tried using a skeleton with fewer parts/a smaller atlas (maybe 256x256)?
Can you try exporting binary skeleton data too?
Was there nothing logged the whole time? No exception that keeps getting thrown?
Have you also tried calling System.GC.Collect()
, 1 Update after instantiating?
I want to see if it reacts to this, though the ideal is still that there's no spike at all.
I isolated the spine prefab in a scene. When I create it the memory goes from 80 to 336.
GC.Collect calls 5 seconds after with NO effect.
Going to try the binary.
There was nothing logged, no exceptions being thrown.
I so appreciate your help on this. I need to get an answer as I have to release this game very soon.
Have you tried profiling your device hooked onto Unity Editor? Maybe you can find exactly which part is causing a large GC Alloc? Or if not Unity Editor, Xcode?
Does this happen with all your skeletons or just a specific one?
Yes, I have profiled it. Can't pinpoint exactly where the issue is coming from. I am profiling using Unity profiler from iOS device (iPhone6 and iPad). What Xcode is showing and what Unity is showing is different when you add it all up. Xcode is more memory.
Profiling it the editor I see a 200+ meg jump in total allocated memory
Image removed due to the lack of support for HTTPS. | Show Anyway
The red is Total GC Allocated the purple is GC Allocated. You see GC Allocated spikes and Total GC Allocated jumps to 270 MB from 67 MB.
In the editor I tested calling System.GC.Collect() and it did recover memory. ON DEVICE it did NOT! Also calling Resources.UnloadUnusedAssets() recovered some memory as well in the editor. But NOT on device.
26 May 2016 1:55 pm
Ok, so I added a continuous System.GC.Collect() at an interval and it DID release it after a bit taking it down to 300 megs. Putting the actual spine file at about 20 meg which seems completely reasonable to me. But what is with this huge spike? What is creating this allocation?
Thanks again for the help.
I have no idea because I'm unable to reproduce the problem in Unity Editor with any of the sample and my own skeletons. (I assume it also doesn't happen on your Unity Editor even if it's set to an iOS target.)
Did you say it happens with a specific skeleton, or any? If it's a specific skeleton, could you send the json and files to unity@esotericsoftware.com ? (if it's any skeleton, that probably won't help)
Did you also manage to check binary export?
I'm almost certain it has something to do with IL2CPP, something arbitrary that it doesn't like.
I couldn't get the binary export to work. It would not import and create the SkeletonData.
Sending you my files straight away. I will also give you specific image import settings in a screenshot.
I tested with a different spine file and it doesn't have this issue. So this specific spine file I sent you does. Interested to get your thoughts on it.
Hopefully, we find the cause.
27 May 2016 11:30 pm
So, good news, the problem seems to show up even in Unity Editor, but only with the skeleton json you sent. I'll try to debug from here.
Thank you so much!
Could you also send your .spine project file?
Your skeleton json is unusually large and it's difficult to edit to isolate the cause.
28 May 2016 12:09 am
I notice that your json was exported in 3.2.01. The spine-csharp 3.2 loader should be able to load binaries.
By the way, binary is a good idea if you're this close to release and want to optimize for speed and size, especially if your json ends up 7MB big like yours.
Sent. Thanks.
I see the 3.1 loader with the 3.2 beta. Is that the runtime you refer to or is there a 3.2 runtime I am missing? I will try that for sure.
Edit: Also is there an easy way to see what version of loader/runtime I am using? I have scoured the source files looking for a version but can't find one.
27 May 2016 10:25 am
Yes, I did both 3.1 and 3.2 beta on top and the skel.bytes imported the skeleton.
Just some info, and it applies to anyone else:
I notice you did a lot of keying-every-property in your animations, resulting in 200 timelines (the runtime object for each row you see in the dopesheet) and even over 300 timelines per animation. You can see this in the Metrics view in animate mode.
In skeletons like yours with well over 100 animations, this can get out of hand really quickly, making managing your keys more difficult (you're not sure which timeline is actually doing something, and you have to scroll around to find the items you actually want).
At runtime, these timelines add up to slow down both animation performance and load time (especially when using JSON) and makes file sizes worse.
In the context of having tested exporting your skeleton with only 10 animations from it and seeing around 11MB allocated, it seems believable that 200+ timeline-heavy animations in json format would add up to 200+MB of memory allocations.
So I tried exporting a binary file (.skel.bytes).
The GC Alloc went from 200+MB (json) down to 20+MB.
The json file is also 7MB, and the binary file is 2MB.
I believe this is the immediate answer to your current problem.
(1) Export your skeleton as Binary (extension: .skel.bytes). Image removed due to the lack of support for HTTPS. | Show Anyway
(2) replace the SkeletonJSON field of your SkeletonData asset inspector with the .skel.bytes file.
Of course, you can delete the .json file from your project after this.
regarding the runtime, I used the current spine-unity.unitypackage, then imported the spine-csharp-beta2.unitypackage from this thread: Noteworthy Spine-Unity Topics
YES! I just tested this myself and sure enough no issue. Thank you, thank you!