For the more experienced people out there, are there any helpful tips on what you should and shouldn't do inside of C# in the Unity environment?
Oh boy, long topic.
This is a general .Net question - basically, objects exist until the last reference is gone, no matter if that reference was in a static or an instance property. If you Destroy an object that is being referenced by another class, it's likely that an exception will be raised the next time the other class attempts to access that Game Object.
Give it a shot and document what happens. :-)
No particular reason, no. On the contrary, I actually like to keep as much code as classes instead of MonoBehaviors, for several reasons:
There is no reason why those classes shouldn't be garbage-collected, other than a bug in the Mono GC.
I have no reason to believe that the GC will not behave as expected, but see above about using destroyed references.
In general, the main gotcha I've found that people run into is that they tend to forget that even if they're running in a memory-managed environment, they should still think about allocation. If you go crazy with allocating and de-allocating large chunks of memory, chances are that you'll end up in a situation that:
Keep your allocations small, and if you allocate a large buffer consider re-using it instead of destroying it (for instance, wiping out a large matrix of values and using the same one, instead of re-allocating different sizes across iterations).
More on memory fragmentation in Mono.
There's one catch with this case: calling delegates on MonoBehaviours that are Destroy()ed but not yet cleaned up (i.e., in the frame between the Destroy() call and the actual removal of the object from memory). This will cause errors if you then try to call any Unity API functions on that object inside the delegate.
The simplest fix I've found is to wrap such delegates in an if(this) block, like so:
It looks like MonoBehaviours and other Unity objects override == to behave as if they are null when they've been destroyed, which is why this works (in normal C# context, this != null is nonsensical).
answered Dec 30, 2009 at 06:22 PM
Worth a mention...
C#/CIL does support value types. If you declare an object as a "struct" it will be allocated on the stack and copied by value, just like primitives. (The only exception is occasions where the value needs to be "boxed", e.g. if you reference it with a vanilla "object" handle type).
Lots of Unity's small object types (e.g. Vector3) are structs and don't affect garbage collection at all (except indirectly when they're used as instance members). So the following:
Doesn't actually cause a heap allocation, it just ensures that the memory is initialized (Lippert's blog "Adventure's in Coding" goes into more detail about this).
If you have small types, you can declare them as structs and take advantage of this. Just don't go crazy - a struct with 100 members will be a lot slower than a class (imagine each function call as taking 100 arguments :P).
answered Jan 07, 2010 at 07:51 PM
Although there's nothing technically wrong with referencing a game component in a static variable, in my experience this is almost always a bad idea. There's usually a way to refactor your code to avoid it.
Now, is there a place for statics? In my experience, they can be convenient in the following situations:
answered Nov 16, 2009 at 07:12 PM
I am currently trying to work around a memory leak by using static variables. It seems that accessing member variables in a certain context (access by delegates run by threads in a thread pool), the object's memory is never released. I haven't finished the workaround yet, but in my test, the problem doesn't occur if no non-static data members are accessed.
answered Aug 24, 2011 at 02:40 AM