Accessing components seems slow
See original GitHub issueHello again,
I’ve noticed functions returning components are surprisingly slow: GetComponent<>(), GetTransform() and AddComponent<>() seem to take significantly more time in C++ than they do in C#.
I’ve benchmarked with those two scripts: C#:
int numObjsToInstantiate = 2500;
GameObject go;
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i=0; i<numObjsToInstantiate; i++)
{
go = new GameObject();
go.GetComponent<Transform>().parent = transform;
go.AddComponent<MeshFilter>();
go.AddComponent<MeshRenderer>();
}
sw.Stop();
print("Elapsed time: " + sw.ElapsedMilliseconds);
C++
int numObjsToInstantiate = 2500;
std::clock_t start = std::clock();
for (int i = 0; i<numObjsToInstantiate; i++)
{
GameObject go;
go.GetComponent<Transform>().SetParent(GetTransform());
go.AddComponent<MeshFilter>();
go.AddComponent<MeshRenderer>();
}
float diff = (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000);
char buf[256];
sprintf(buf, "Elapsed time: %d ms", (int)diff);
Debug::Log(String(buf));
The C# script runs in roughly 30 milliseconds. The C++ one takes 20 seconds.
I’m using Unity as a scene viewer for data from an old game, meaning I’m building the whole scene in Start() and adding a few hundred/thousands of components, setting parents for transforms, etc. In my case it’s no big deal since it only runs once, but I thought the difference was a bit strange.
(I had no performance issue with other parts of the Unity API. I’m even able to load hundreds of textures in less than a second, which is a real delight.)
Issue Analytics
- State:
- Created 5 years ago
- Reactions:1
- Comments:5 (5 by maintainers)
Thanks so much for digging into this so deeply! With your findings, the fix was trivial to implement.
String
objects created from string literals weren’t being ref-counted, so I added one line to do that and the test code now works. 🎉Here’s the commit that fixes the issue: 4af035161a3ba682124eda3a47ab9697e6068557
Please let me know if you run into any other issues and have fun creating your viewer. 👍
Okay, I made more progress on the issue.
I was wondering why I needed all those 100,000 handles while I definitely wasn’t using that much simultaneously, and ran a few tests. It seems the culprit is System::String, which does not release its handle once it goes out of scope and is destroyed. For instance, I ran the following with as few as 100 handles (enough to make sure my plugin would run, too few for more than 100 simultaneous managed objects):
funcA
runs without issue.funcB
results in a lack of available handles.My importer names all objects, materials and textures, hence creating a lot of strings. I removed all the object naming, and since I’m not creating strings anymore, I can import my whole scene in under a second and with only 100 handles. Yeah ! Well, now all my objects are unnamed, but I can live without it for now.