DEV Community

Discussion on: How does your language handle memory?

Collapse
 
kspeakman profile image
Kasey Speakman • Edited

I'll add to the .NET answer. I've coded in VB, C#, and F# on .NET but never used unmanaged code.

First, the managed side actually has two kinds of memory allocation for two kinds of objects (Reference and Value objects). Reference objects go on the Heap and are tracked by the garbage collector. They can be referenced from any other code. The GC keeps track of which code still has a reference to the objects it manages, so it knows when it can safely free the memory. The GC periodically pauses execution of code to run its mark and compact routine.

The garbage collector is also "generational". When objects are created, they are at Generation 0, which is the most-frequently checked for collection. Longer-lived objects will eventually move to higher generations which don't get checked as often. This avoids needlessly scanning thru objects which will not get collected anyway.

Value objects go on the stack (as in stack trace and stack overflow) and they are not garbage collected. They are local to the stack frame of the running code. When the stack frame exits, the Value object's memory is automatically freed.

Most devs use Reference objects (class in C#) to build their data structures rather than Value objects (e.g. struct in C#). Obviously the Value objects have an advantage because no cycles are wasted with garbage collection management. However, reference objects are often better when an object is "large" (more than 16 bytes, but that is debatable) or is passed around a lot. Since Value objects live and die on the local stack frame, they have to be copied in their entirety when they are passed up and down the stack. (down = calling another method with the object as argument, up = returning the object to the calling method, unless I have those backward). Whereas Reference objects only have their pointers copied between stack frames, not the entire structure. So Reference objects are better to use if they are passed around a lot or they are large in size due to the cost of copying a Value object.

As for using, I have never used it for memory management. I use it to avoid having to manually code a .Close() statement on things like database connections. using basically says "call .Dispose() (and therefore Close for connection objects) whenever this variable goes out of scope." using only works on objects that implement the interface IDisposable. There's no special memory magic to it. See this reference. (I've never used destructors either.)

Collapse
 
nickpolyder profile image
Nick Polyderopoulos

Cool. I dont think that someone in C# (except those who write the clr or the corefx itself or really low level code) have used finalizer or the actual memory allocation statements. I have seen them been used on projects like RavenDB. Same goes for pointers too(int*, byte* etc).
Most of the times the managed pointers are used (delegate, object etc)

Collapse
 
kspeakman profile image
Kasey Speakman

I'll also add that lots of allocations in really "hot" code can make the GC particularly active, reducing performance. In the .NET environment it is common for performance-critical libraries to include in their performance benchmarks the # of GC allocations in each generation.

I am mindful of my usage, but in most everyday scenarios (business programming) I never even have to think about the GC.