Reference types (classes) generally have more significant GC implications than value types (structs).
http://docs.unity3d.com/Manual/MobileOptimizationPracticalScriptingOptimizations.html Look up the section: How to Avoid Allocating Memory It explains how classes are objects, while data is structs.
How to Avoid Allocating Memory Every time an object is created, memory is allocated. Very often in code, you are creating objects without even knowing it. Debug.Log("boo" + "hoo"); creates an object. Use System.String.Empty instead of "" when dealing with lots of strings. Immediate Mode GUI (UnityGUI) is slow and should not be used at any time when performance is an issue. Difference between class and struct: Classes are objects and behave as references. If Foo is a class and Foo foo = new Foo(); MyFunction(foo); then MyFunction will receive a reference to the original Foo object that was allocated on the heap. Any changes to foo inside MyFunction will be visible anywhere foo is referenced. (I think here they mean to type Structs, not Classes) Classes are data and behave as such. If Foo is a struct and Foo foo = new Foo(); MyFunction(foo); then MyFunction will receive a copy of foo. foo is never allocated on the heap and never garbage collected. If MyFunction modifies it’s copy of foo, the other foo is unaffected. Objects which stick around for a long time should be classes, and objects which are ephemeral should be structs. Vector3 is probably the most famous struct. If it were a class, everything would be a lot slower.
There are lots of subtle differences but the main thing is: A) Classes are allocated on the heap and therefor subject to garbage collection B) Structs are allocated on the stack and do not feed the GC However, that doesn't mean that everything should be a struct. Any time you need a reference to something it should be a class. Also, when you pass a class into a method call it actually passes the 32-bit pointer (an integer) to the memory location of the class. Be mindful of what data types and how much data you have in your structs. If it is larger than 32-bits and you're passing it around a lot, then you're actually potentially being less efficient because you're making copies of that data and actually consuming more memory (though still not feeding the GC). Also, there are cases when structs can end up on the heap. If they are fields that belong to a class then that class is allocated on the heap and the fields are as well meaning your struct will actually live on the heap.
Classes are for big, important thingies. You only get one copy of each instance of a class. It lives in the heap. Structs are for small, throw away thingies. You get a new copy every time you pass it around. It lives in the stack. As a Vector3 is small and often throw away, it makes sense for it to be a struct.
What if I have a bunch of little thingies that never go away? Or a bunch of big thingies that i throw away a lot?
You choose. I would suggest a class as being more efficient. This is a loose/loose situation. A class will kill you on GC. A struct will kill you on time to copy around. I would bench mark both and see what comes out best. Its also a good candidate for using a pool
I'm sorry sir, but unless it fits in the overhead compartment you're going to have to check your data. Very true, you're better to use an object pool and recycle those big thingies.
Little thingies never going away - for me it would depend on what I'm doing with it. If they have references in them, I'll probably make them a class. But yeah, I agree with BoredMormon, this is a you choose situation... neither really have a benefit in this case with out more detail about what they specifically do. An example I might lean towards class is that it needs to implement an interface, and I know for a fact that where ever it gets used it's going to be referenced as an interface. This means it will be boxed. So might as well just make it a class seeing as it'll be living on the heap anyways... so rather than having an implied boxed reference, go with the full reference. A bunch of big thingies that you throw away a lot - now this one is a problem I run into a lot, it may also be small class just like above with the interface. Here I'll implement an object pooling creational pattern. I'll have a static pool of objects that cache them for reuse. I actually have the pool class set up for easy implementation: https://github.com/lordofduct/space...SpacepuppyBase/Collections/ObjectCachePool.cs One place I use it a bit is with my RadicalCoroutine class: https://github.com/lordofduct/space...lob/master/SpacepuppyBase/RadicalCoroutine.cs With it I allow implementing your own wait instructions via my IRadicalYieldInstruction interface, and I treat everything as that. For ease I wrap enumerators that come back in an implementation of that, which is small but exists for small periods of time. So you can see how I cache them here: Code (csharp): private class EnumWrapper : IRadicalYieldInstruction, IPooledYieldInstruction { private static com.spacepuppy.Collections.ObjectCachePool<EnumWrapper> _pool = new com.spacepuppy.Collections.ObjectCachePool<EnumWrapper>(-1, () => new EnumWrapper()); public static EnumWrapper Create(IEnumerator e) { var w = _pool.GetInstance(); w._e = e; w._complete = false; return w; } internal IEnumerator _e; private bool _complete; private EnumWrapper() { } public bool Tick(out object yieldObject) { if(_e.MoveNext()) { yieldObject = _e.Current; return true; } else { _complete = true; yieldObject = null; return false; } } public bool IsComplete { get { return _complete; } } void System.IDisposable.Dispose() { _e = null; _pool.Release(this); } } Or I have an implementation of WaitForSeconds called WaitForDuration. With this I allow integrating my SPTime class and define which kind of time (real, gametime, or a custom time as I allow creating multiple custom independently scaling times). Again these get used a lot, so I cache them: https://github.com/lordofduct/space...er/SpacepuppyBase/IRadicalYieldInstruction.cs Code (csharp): /// <summary> /// Represents a duration of time to wait for that can be paused, and can use various kinds of TimeSuppliers. /// NOTE - this yield instruction is pooled, NEVER store one for reuse. The pool takes care of that for you. Instead /// use the static factory methods. /// </summary> public class WaitForDuration : IPausibleYieldInstruction, IPooledYieldInstruction, IProgressingYieldInstruction { #region Fields private ITimeSupplier _supplier; private float _t; private float _cache; private float _dur; #endregion #region CONSTRUCTOR private WaitForDuration() { } private void Init(float dur, ITimeSupplier supplier) { _supplier = supplier ?? SPTime.Normal; _dur = dur; this.Reset(); } #endregion #region Properties public float Duration { get { return _dur; } } public float CurrentTime { get { return (float.IsNaN(_t)) ? _cache : (_supplier.Total - _t) + _cache; } } #endregion #region IEnumerator Interface bool IRadicalYieldInstruction.IsComplete { get { return this.CurrentTime >= _dur; } } float IProgressingYieldInstruction.Progress { get { return Mathf.Clamp01(this.CurrentTime / _dur); } } bool IRadicalYieldInstruction.Tick(out object yieldObject) { yieldObject = null; return this.CurrentTime < _dur; } public void Reset() { _t = _supplier.Total; _cache = 0f; } void IPausibleYieldInstruction.OnPause() { _cache = (_supplier.Total - _t) + _cache; _t = float.NaN; } void IPausibleYieldInstruction.OnResume() { _t = Time.time; } #endregion #region IPooledYieldInstruction Interface void System.IDisposable.Dispose() { _pool.Release(this); } #endregion #region Static Factory private static com.spacepuppy.Collections.ObjectCachePool<WaitForDuration> _pool = new com.spacepuppy.Collections.ObjectCachePool<WaitForDuration>(1000, () => new WaitForDuration()); public static WaitForDuration Seconds(float seconds, ITimeSupplier supplier = null) { var w = _pool.GetInstance(); w.Init(seconds, supplier); return w; } public static WaitForDuration FromWaitForSeconds(WaitForSeconds wait, bool returnNullIfZero = true) { var dur = ConvertUtil.ToSingle(DynamicUtil.GetValue(wait, "m_Seconds")); if (returnNullIfZero && dur <= 0f) { return null; } else { var w = _pool.GetInstance(); w.Init(dur, SPTime.Normal); return w; } } #endregion } If you're interested in that ITimeSupplier/SPTime thing: https://github.com/lordofduct/spacepuppy-unity-framework/blob/master/SpacepuppyBase/SPTime.cs https://github.com/lordofduct/spacepuppy-unity-framework/blob/master/SpacepuppyBase/ITimeSupplier.cs