1
\$\begingroup\$

I'm doing a lot of 3D math in my game engine loop using typical classes like Vector3D, Matrix4x4, Plane3D, etc. Currently every operation causes a new object to be created for the result value. The number of new objects created causes a stutter whenever the GC kicks in.

In this simple vector operation, 2 new Vector3D objects are created, one at the divide and one at the multiply operator.

// C#
result = (v / len1) * len2; // where len* is a `double`

I happen to know some C++, so an optimized version would create a disposable object on the stack and pass that to the individual ops, thereby automatically disposing off the temporary objects at the end of the function (also avoiding the GC altogether), something like this:

// C++
Vector3D result;
v.divideBy(len1, &result);
result.multiplyBy(len2, &result);

But as you can see its cumbersome and unreadable. So what are commonly used memory optimization strategies used by pro C++ gamedevs to optimize vector math? I'm looking for general platform agnostic solutions that can be implemented in C# and other high-level languages, although C++ memory tricks are also appreciated.

\$\endgroup\$
  • 1
    \$\begingroup\$ Is vector3d class or struct? In c# struct is on the stack so no gc is done for those temporaries. \$\endgroup\$ – Steven Oct 19 '15 at 13:52
  • \$\begingroup\$ Are you running your tests in debug or release? Are there outputs in the debug window showing some other kinds of problems? What tools have you used to assess that this is the bottleneck? \$\endgroup\$ – Steven Oct 19 '15 at 14:26
  • \$\begingroup\$ There's operator overloading in C++, ya know. You don't have to write the vector code any different than the C# example above. The C++ version you have looks closer to C code than C++. As for C++, it's pretty simple -- just don't allocate each vector on the free store, e.g. Use the stack: Vector3D result = (v / len1) * len2; or store multiple vectors in contiguous blocks (arrays, e.g.), so that they don't have to be allocated individually. For speed it helps to use SPFP instead of DPFP, and SoA reps can be useful for cases where you do a boatload of vector/matrix math. \$\endgroup\$ – user77245 Dec 13 '17 at 8:28
4
\$\begingroup\$

Are you sure that the matrix operations are causing the slowdown? In C# most Vector libraries implement their types as structures, which are not generally allocated using the garbage collector, but are instead created on the stack. The temporaries in your example don't cause allocations that need to be collected.

\$\endgroup\$
  • \$\begingroup\$ Yes, they were all classes. Changed to structs for huge speedup. Thanks! \$\endgroup\$ – Robinicks Oct 20 '15 at 13:35
3
\$\begingroup\$

Currently every operation causes a new object to be created for the result value. The number of new objects created causes a stutter whenever the GC kicks in.

Make sure your math types are value types (structs); value types don't create garbage (unless boxed inside a reference type).

If your math types are already value types, use a profiler, because the GC hitches you're seeing aren't directly caused by what you appear to be assuming they are.

I happen to know some C++, so an optimized version would create a disposable object on the stack and pass that to the individual ops, thereby automatically disposing off the temporary objects at the end of the function (also avoiding the GC altogether), something like this:

C# doesn't have RAII, and the IDisposable pattern is for disposing unmanaged resources (or managed resources that are themselves IDisposable because they contain unmanaged resources). Using it for math types will not optimize anything.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.