Die, You Gravy Sucking Pig Dog!

In the C programming language, you're regularly forced to deal with the painful, dangerous concepts of pointers and explicit memory allocation.


This is a companion discussion topic for the original blog entry at: http://www.codinghorror.com/blog/2009/01/die-you-gravy-sucking-pig-dog.html

C- Not your best work.

@Oliver:
c = null;
DoSomethingElse();
…By setting it to null this allows it to be garbage collected before DoSomethingElse is called…
That is wrong, you should read your learning .Net book again, the GC does not run immediately and the GC does not destroys the objects right away, first marks the objects and then destroys them, and besides that the GC only starts working when the free memory is getting low, you need to add this to your code to do what you think
GC.Collect();
GC.WaitForPendingFinalizers();
Which is a bad idea, setting a variable to null in .Net its just being ignorant of how the Garbage Collector works.

Ugh, you act as if using the heap is a chore. Using the heap can be easy, especially if you properly implement it using RAII (Resource Acquisition Is Initialization)

There are many things wrong with this post.

@James:It would clear a lot of the misconceptions up – Dispose pattern, when to explicitly set something to null, etc.
The point is that setting something to null is not necessary, from the page you linked http://msdn.microsoft.com/en-us/library/ms998547.aspx :
Garbage Collection Explained point 3
The object dies due to all its references either being explicitly set to null or else going out of scope.
going out of scope is the key, if you don’t set something to null the object will be collected even if its not set to null.
Set Unneeded Member Variables to Null Before Making Long-Running Calls
Before you block on a long-running call, you should explicitly set any unneeded member variables to null before making the call so they can be collected. This is demonstrated in the following code fragment.
class MyClass{
private string str1;
private string str2;

void DoSomeProcessing(…){
str1= GetResult(…);
str2= GetOtherResult(…);
}
void MakeDBCall(…){
PrepareForDBCall(str1,str2);
str1=null;
str2=null;
// Make a database (long running) call
}
}

That is bad code because is not well factored, first, why do you have unneeded member variables?, if they are not needed after some point those variables don’t belong to that method, so that class can become something like this:

class MyClass{
void Init(…){
string str1= GetResult(…);
string str2= GetOtherResult(…);
PrepareForDBCall(str1,str2);
}
void MakeDBCall(…){
Init()
// Make a database (long running) call
}
}
the point is that in the first example null was necessary because of a bad design, but that does not mean that you need it in order to mark a variable to be collected.

Juan Zamudio

I suggest you spend more time programming and less time making a fool out of yourself. The world would be a better place.

I mean what the fuck does this:
b1 = (double )malloc(msizeof(double));

have to do with this:
Double b1

besides using the same variable name?

And letting the GC close sockets? Dear God, please save me from any software written by Jeff Atwood or any of his hangarounds, Amen.

WAIT! Wait, wait, wait, wait… In C++, stack variables get cleaned automagically, heap variables have to be manually cleaned and that’s only if you don’t use auto_ptr or boost::smart_ptr (which will be in the next standard).

Now, you’re telling use that GC languages are so much better yet there are dozens post above me that clearly say that you should through some hoops to have your vars cleaned up…

I’m not sure I’m getting it. To be clear:

C++ stack variable:
{
int i;
}

C++ heap variable:
{
auto_ptrint pi = new int;
}

Garbage collected C# (from a post above):
{
using(var disposable = … create disposable …)
{
disposable.Close(); // Or whatever the ‘close’ method of the type is.
}
}

And somehow that last method is… better? Have I fallen in bizarro-land during lunch?

If you work in scientific computing like I do, automated GC just doesn’t cut it. Come all ye Optimizationers and Algorithmaniacs to the computational electromagnetics world.

What? Jeff learned C?!

Obviously not as others have pointed out the C example is allocating an array of doubles on the heap.

The second example is allocating a single double on the stack.

Garbage collection is all well and good until you get something like this: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4907801

In that bug(which according to Java devs is NOT a bug) If you create a popup on a window, a static reference to that window(and all it’s associated resources) is held until you do another popup, never mind that your app only uses that window once for config, then goes to background and never shows up again. All the resources pointed to by the window are held(which could include references to huge chunks of memory) since they are reachable from the root.

What do you do here? Trust the runtime? Trust the garbage collector? Or do as the customer did and reflectively null it out?

Just a note about Close+Dispose, in hopes that it will help some other programmer.

I see a lot of:

file.Close();
file.Dispose();

I’ve done it myself to fix some issue where a later open on the same file failed due to file locked issues, but the issue never completely went away, no matter how many times we closed the file. Finally, we figured it out.

file.Close() works as advertised, as does file.Dispose(). However, many virus checkers will watch for the Close() and will immediately scan the file. This locks the file until the scan is created, creating a race condition between the virus checker and the next time the program tries to open the file. Close+Dispose works because it is an inconsistent race condition and you got lucky.

@Juan: Re-read my comment. I didn’t state setting variables to null is a good practice. The article, as you pointed out, clearly did not either. Also, your deconstruction of that code example does not change the point the article was making. If you have static or instance variables that are no longer needed, explicitly setting them to null before long running operations can be beneficial.

Would I use that specific example with developers I teach? Most likely never. LOL! But, if I had no choice I could make it work as pedagogical tool. For less experienced .NET developers, it would serve well to illustrate the general idea and syntax of setting non-local variables to null explicitly. While for the more knowledgeable developers it could be leverage to teach how in some cases you could avoid it altogether just as you did.

I agree wholeheartedly, but given the sophistication of this site would offer one corrolary - in certain cases a human developer will pound the stuffing out of a garbage collector, but a very specific set of conditions need to hold true.

1 - the primary stressor on memory comes from dynamic management of a large number of homogeneous objects.

2 - the developer is highly skilled in techniques such as STL allocators, OS page mapping, etc.

In this specific situation, you will find that the optimal solution is to implement a highly specialized memory management system that exploits the homogeneity of the object collection, using large block allocations from the OS and demanding more proactive management (create and release) of the client software - 3D graphic engines, low level or large scale network applications and other seriously furball applications benefit -

Secondly, there’s one further optimization in GC land that I didn’t see called out. In general one should leave the garbage collector alone, and let it do it’s thing. However, in a situation (often seen in low level 3D render loops) where

  1. the iteration cycle time is slightly in excess of the Generation 0 threshold time
  2. a large number of object allocations are done where the object lifetime is scoped to a single pass
    then it can be beneficial to trigger the garbage collector at iteration start - the reason for this is that a generation scavenging gc assumes that if the lifetime of an object is not very short then it may be very long (this is dependent on implementation, # of generations, etc) - in certain (specific and measurable cases) you can get an aliasing problem where the lifetime of a large number of objects causes them to (incorrectly) pass these generational boundaries and be preserved for too long a time - the symptom is that memory consumption (careful how you measure, as the gc is dealing with things it thinks are in use but it hasn’t actually checked) shows a distinct sawtooth pattern - swells and swells and swells, then the machine chokes up for a bit (the full scan runs, effectively a complete mark and sweep pass) and the memory footprint shrinks by an order of magnitude.

Certainly an edge case, but given the sophistication of the readers here, one they’re more likely to bump into, I would guess - certainly the average enterprise developer is better off with a GC and should just leave it alone to do it’s job
Mark

A value type is on the stack. It will be stack collected, just like a int a; would in C. The comparison is completely bogus.

Setting a reference type to null or 0 does nothing in .NET, except in cases where you later re-use the variable (which denotes bad programming habits). Actually, let me say that it’s even worse, and could actually cause the GC to take even longer to collect the memory.

ALWAYS ALWAYS ALWAYS Close/Dispose unmanaged files/connections/etc. It doesn’t matter if you have the biggest server in the world, the connection pool will scream uncle long before your connection does. It will kill your app, and is in no way an optimization.

The using keyword is the easiest, cleanest way of dealing with IDisposable types, and should be every developers way of managing the lifetime of things like connections and files.

I chuckle a bit that Mullin above continually refers to the sophistication of the readers here. If they were sophisticated, Jeff, you would be shamed into unpublishing this nonsense.

I find it kinda funny that Double b1; is Jeff’s example of newing something up. Besides the lack of the word new, aren’t value-types stored on the stack in C# anyway?

Jeff, you still have to alloc the bl variable: Double bl = new Double();

Obviously not as others have pointed out the C example is allocating an array of doubles on the heap. The second example is allocating a single double on the stack.

I agree, it’s not a perfect example – but that’s the first C code snippet I could find that used malloc().

Double[] b1 = new Double[m];

Thank you, I made the correction.

Please forgive the poetic license. I am, truly, the world’s worst C programmer.

@James:
If you have static or instance variables…
I thought static variables were ignored by the Garbage Collector.
I think you can use anything as long as you know why (avoid Voodoo programming), I have seen people using VB.Net like VB6, parameters by reference, String to concatenate, optional parameters (instead of overloads), the list goes forever, I’m from Mexico and most people where I work don’t understand English (my English is not that good either), and the documentation in Spanish is very lame and scarce, maybe that’s the reason I see a lot of mistakes like that.

Bringing things full circle, the phrase Die, you gravy sucking pig dog! is likely derived from a routine in Steve Martin’s 1978 A Wild and Crazy Guy album:


his first writing experience was composing cheers for the team. But the other cheerleaders, he tells audiences, were so jealous they wouldn’t use my cheers. I wrote, ‘Die, you gravy-sucking pigs’.

Why is learning C such a bad thing? This is just a weird view. Don’t get it. Especially when it seems like the main point of this blog is, presumably, to promote the love of coding and computer programmer; as well as the promote becoming a better programmer. I dunno. Just seems odd.

If advantages of using GC were really beneficial, we would be basking in the glow of totally error-free software, without memory leaks, without buffer overruns.

Reality is, of course, very different. 90%+ of all security problems with software have been tracked to poor memory/resource handling in code.

If this isn’t a proof by contradiction, I do not know what is.

GC is a nice academic concept. In the real world, it is a pain in the neck because it is non-deterministic. Yes, you can force it to run when you want it, but that’s the same as cleaning up after yourself, isn’t it?