In the C programming language, you're regularly forced to deal with the painful, dangerous concepts of pointers and explicit memory allocation.
b1 = (double *)malloc(m*sizeof(double));
In modern garbage collected programming languages, life is much simpler; you simply new up whatever object or variable you need.
Double[] b1 = new Double[m];
Use your objects, and just walk away when you're done. The garbage collector will cruise by periodically, and when he sees stuff you're not using any more, he'll clean up behind you and deal with all that nasty pointer and memory allocation stuff on your behalf. It's totally automatic.
Pretty awesome, right? I'd wager the majority of programmers alive today have never once worried about malloc(). I call this progress, as does Jamie Zawinski:
Based on my experience using both kinds of languages, for years at a stretch, I claim that a good garbage collector always beats doing explicit malloc/free in both computational efficiency and programmer time.However, I also claim that, because of the amount of programmer time that is saved by using GC rather than explicit malloc/free, as well as the dramatic reduction in hard-to-debug storage-management problems, even using a mediocre garbage collector will still result in your ending up with better software faster.
Most of the time, throwing memory and CPU at the problem is still cheaper than throwing programmer time at the problem, even when you multiply the CPUs/memory by the number of users. This isn't true all the time, but it's probably true more often than you think, because Worse is Better.
But even for programmers who have enjoyed automatic garbage collection their whole careers, there are still some.. oddities. See if you can spot one here:
sqlConnection.Close(); sqlConnection.Dispose(); sqlConnection = null;
That is one hellaciously closed database connection. Why don't you take it out back and shoot it, while you're at it?
Even with your friendly neighborhood garbage collector making regular rounds on commodity desktops/servers where many gigabytes of main memory are commonplace, there are still times when you need to release precious resources right now. Not at some unspecified point in the future, whenever the GC gets around to it. Like, say, a database connection. Sure, your database server may be powerful, but it doesn't support an infinitely large number of concurrent connections, either.
The confusing choice between setting an object to null and calling the Dispose method doesn't help matters any. Is it even clear what state the connection is in after Close is called? Could the connection be reused at that point?
Personally, I view explicit disposal as more of an optimization than anything else, but it can be a pretty important optimization on a heavily loaded webserver, or a performance intensive desktop application plowing through gigabytes of data.
Of course, your average obsessive-compulsive developer sees that he's dealing with a semi-precious system resource, and immediately takes matters into his own hands, because he can do a better job than the garbage collector. K. Scott Allen proposes a solution that might mollify both camps in Disposal Anxiety:
What the IDisposable interface needs is a method that promotes self-efficacy in a developer. A method name that can stir up primal urges as the developer types. What we need is a method like the one in BSD's shutdown.c module.
die_you_gravy_sucking_pig_dog() { char *empty_environ[] = { NULL }; syslog(LOG_NOTICE, "%s by %s: %s", doreboot ? "reboot" : dohalt ? "halt" : dopower ? "power-down" : "shutdown", whom, mbuf); (void)sleep(2); (void)printf("\r\nSystem shutdown time has arrived\007\007\r\n"); if (killflg) { (void)printf("\rbut you'll have to do it yourself\r\n"); exit(0); }Now, I know this function was written back in the days when steam engines still ruled the world, but we could modernize the function by applying some .NET naming standards.
sqlConnection.DieYouGravySuckingPigDog();Can you feel the passion behind this statement? This statement carries the emotion that is hard to find in today's code. I hope you'll support this proposal. Good people will be able to sleep at night once again.
So the next time you feel anxious about letting objects fall out of scope, remember: you could always terminate them with extreme prejudice, if you feel it's necessary.
But it probably isn't.
C- Not your best work.
ProfessorTom on January 15, 2009 1:05 AM@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)
LavosPhoenix on January 15, 2009 1:49 AMThere are many things wrong with this post.
Joe Chung on January 15, 2009 1:56 AM@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
Juan Zamudio on January 15, 2009 2:09 AMI 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(m*sizeof(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.
Adde on January 15, 2009 2:17 AMWAIT! 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?
W on January 15, 2009 2:22 AMIf 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.
chris on January 15, 2009 3:01 AMWhat? 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.
Grom on January 15, 2009 3:14 AMGarbage 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?
Z on January 15, 2009 3:24 AMJust 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.
Doug on January 15, 2009 4:04 AM@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.
James Arendt on January 15, 2009 4:33 AMI 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.
Just A Guy on January 15, 2009 5:21 AMI 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.
Jeff Atwood on January 15, 2009 5:22 AM@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.
Charles on January 15, 2009 5:44 AMIf 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?
BugFree on January 15, 2009 5:45 AMShame, we can almost get there....
using System;
class SqlConnection: IDisposable
{
public void Dispose() {}
public void Close() {}
}
static class SqlConnectionExtensions
{
public static void DieYouGravySuckingPigDog(this SqlConnection connection)
{
connection.Close();
connection.Dispose();
}
}
class Program
{
static void Main()
{
SqlConnection c = new SqlConnection();
c.DieYouGravySuckingPigDog();
c = null; // Blast...
}
}
Use an extension method, almost...
Tom Kirby-Green on January 15, 2009 5:49 AM sqlConnection.Close();
sqlConnection.Dispose();
sqlConnection = null;
That is one hellaciously closed database connection.
You can avoid this by using 'using' :
using (SqlConnection conn = new SqlConnection(Server=localhost; Database=myDatabase;))
{
SqlCommand command = conn.CreateCommand();
command.CommandType = CommandType.Text;
command.CommandText = SELECT myField FROM myTable;
conn.Open();
int i = (int) command.ExecuteScalar();
}
Or for that matter use C++/CLI where you can declare your reference type 'on the stack' (at least from a syntax perspective) and the compiler will automatically do the deterministic call to Dispose when you leave the scope.
Tom Kirby-Green on January 15, 2009 5:51 AMTrue, you can use things like extension methods and/or wrapper classes for things like this (for example, we've a connection wrapper here that, along with it's other uses, has it's own 'open/close' which performs the close/dispose/null on it's own...
But there are many objects or classes like that which have a Close() a Dispose() and then, well, there's the good ole =null. Not having to do that in the first place is what I think the point of the article was at...?
Mal on January 15, 2009 5:57 AMSo, GC is great, right? Throw cpu cycles at it - they're basically free, after all!
Yeah, do that on a 400MHz embedded ARM9. The art of mallocing and freeing is still *pretty* important for a lot of applications.
Justin on January 15, 2009 6:02 AMI'm primarily a PHP programmer and I find myself calling the unset() function regularly and this is entirely down to being a little obsessive about resources. A typical page load lasts less than a second and with the amount of servers our company has we're nowhere near capacity, but for some unknown reasons in my subconscious; I still feel the need to keep the memory usage as low as possible.
Explicitly setting sqlConnection to null is a legacy of the classic VB/COM days when these things were reference counted.
I thought that carrying it over into .NET and other programming languages with modern generational garbage collectors is more a case of ignorance and/or cargo cult programming than anything else.
James McKay on January 15, 2009 6:05 AMWhat? Jeff learned C?!
Aviv Ben-Yosef on January 15, 2009 6:05 AMThis is an area where using dependency injection shines, as you can easily do deterministic disposal of all instances requested from your container.
Autofac in particular handles this scenario very well:
using (var inner = container.CreateInnerContainer())
{
var component = inner.ResolveSomeComponent();
// component, and any of its disposable dependencies, will
// be disposed of when the using block completes
}
Ronald: I think you completely missed the point of what was being said. Of course you can use using to avoid that. The point is to show how overzealous programmers get when trying to clean up resources, when it really isn't necessary.
Charles Boyung on January 15, 2009 6:16 AM
Very funny.
However, I would recommend just using a database connection pool.
In Java-land (where I spend most of my time) you can even go further. After setting the variable to null you can call System.gc() which forces the garbage collector to run Right Now.
Aviv, no of course he didn't learn C. He would definitely write a blog entry so we could all know to stop chastising him about it.
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?
Ryan Fox on January 15, 2009 6:19 AMFrom now on I'm putting the following code in all my programs...
//Holy crap!, that's one hellaciously
//closed database connection
sqlConnection.Close();
sqlConnection.Dispose();
sqlConnection = null;
In general, any object having both Close Dispose, you're ok calling only one.
It's true dispose shouldn't be required to be called, but some API's (*cough* AutoCAD *cough*) get all sorts of pissed off if things get disposed/finalized in the wrong order.
Wyatt on January 15, 2009 6:27 AMThere is always a give and take, but overzealous or not, it's never a bad thing to think in terms of efficiency.
While I wouldn't go so far as to set the object as null, I will indeed dispose of (or use a using block**) everything I can when I'm done with it, I think it's just prudent to not ignore such a small and easily implemented optimization.
Maybe it's just that my co-worker has been beating ultra optimization into my head for over a year now though, he is very zealous about optimizing his code, but it makes sense to go ahead and dispose of it....now if only I had a GC to take my trash to the dumpster for me....
Mat on January 15, 2009 6:32 AMContrary to what you seem to think, it is NOT necessary to use malloc() for every variable in C. It's also not necessary to use malloc() if you need to call a function that takes a pointer. It's much easier to use (address-of operator). The only time I can think of that you need to use malloc() is when you don't want the variable to be automatically deleted when the function ends.
But I agree that languages that allocate everything with the new operator, like Java, need a garbage collector. If they didn't have a garbage collector, people would use a language that allocated most things on the stack, like C and C++.
Nate on January 15, 2009 6:32 AM@Sarel Botha: I'm fairly sure the System.gc() call in Java merely suggests that the VM do garbage collection immediately. I don't think the programmer can really force it to run at all.
JG on January 15, 2009 6:36 AM@Nate: Sometimes, your object is too large to live on the stack, so you have to put it on the heap, regardless of how long it will live.
Ryan Fox on January 15, 2009 6:39 AMWhat C programmer would put the explicit cast in the malloc call??? The two lines don't mean the same thing either.
It should be:
double* b1 = malloc(m*sizeof(double));
if(b1 == NULL) exit(1); /* it just seems wrong to leave this out even in a demo! */
vs
Double[] b1 = new Double[m];
Of course the real point here is disposing of resources, which can get ugly.
free(b1);
b1 = NULL; /* optional */
vs
nothing!
(And it gets really fun when you consider error handling.)
But that isn't necessarily garbage collector; C++ does the same with RAII:
std::vectordouble b1;
[...]
// it cleans itself up!
I'd wager the majority of programmers alive today have never once worried about malloc(). - And you'd be very, very wrong. Anyone who has ever used C, C++ or relatives, or has written an interface to a C library from a higher-level language, has dealt with explicit memory allocation.
It would be very depressing to find that that doesn't constitute the majority of programmers...
Robert Synnott on January 15, 2009 6:44 AM
Hopefully someone with more knowledge than Jeff and more time than myself will explain why it is better to explicitly dispose certain resources rather than leaving it up to the GC.
@JG: It's probably an implementation-dependent things, but in a lot of high-level languages you can indeed force a GC immediately.
Robert Synnott on January 15, 2009 6:45 AMsqlConnection.Close();
sqlConnection.Dispose();
sqlConnection = null;
You forgot to put this in a try / finally block.
Eric on January 15, 2009 6:49 AMThere are a lot more programmers that have written C than you think, not everyone comes from a Visual Basic application writing background.
You've given us yet another implicit example of why learning C is really a necessity for becoming a well rounded programmer.
Just recently, I saw this in an application I was working on:
try
{
cmm.ExecuteNonQuery();
}
catch (Exception ex)
{
conn.Close();
conn.Dispose();
Application.Exit();
return;
}
The garbage collector will cruise by periodically, and when he sees stuff you're not using any more, he'll clean up behind you and deal with all that nasty pointer and memory allocation stuff on your behalf. It's totally automatic.
The garbage collector is male?! How come it's not female? ;)
Mehrdad on January 15, 2009 6:56 AMFrom MSDN:
GC.Collect()
Forces garbage collection of all generations.
This is a .Net Framework call - C#, VB.Net, etc...
And on rare occasions I've had to use it.
Nchantim on January 15, 2009 6:57 AMI used malloc once or twice...but what about c++'s new and delete? That's what I remember the most from my early days of programming.
Joe Beam on January 15, 2009 6:58 AMIn C# the easy way is
using(var sqlConnection=Connect()) {
... use the connection ...
}
this causes Dispose to be called on the connection when you leave the block: doesn't matter if you fall out the bottom, leave via return or continue or throw.
My own preference is to use Nuke. Shorter but just as passionate. And have you ever noticed that no one deletes a folder? They blow it away. Too many hours playing Doom I suppose.
Mike on January 15, 2009 7:02 AMbut what about c++'s new and delete?
C++ has had deterministic allocation and disposal of memory and other resources via autoptr for years, I don't think I used explicit allocation for most of my 96-2003 C++ career.
Ryan Roberts on January 15, 2009 7:03 AMThough the modern-day Garbage Collectors claim to be smart and efficient, their non-deterministic behavior pisses me off.
After all, in JAVA, gc() is a mere suggestion to the JVM :p
I still love my free(x) and delete x;
Mohit Nanda on January 15, 2009 7:03 AMI'd wager the majority of programmers alive today have never once worried about malloc()
Oh... I'd better check if my ~35 yo friends are still around, then.
You must have a pretty low life expectancy in the US :) :)
Wojtek on January 15, 2009 7:04 AM@Aaron
I beg to differ on some of your points.
1. Setting a reference to null accomplishes precisely nothing.
consider this:
using (var c = new Disposable())
{
c.DoSomething();
}
c = null;
DoSomethingElse();
Disposing c will release any unmanaged resources it will use, but not all managed resources. The class itself takes some memory and it may contain references to other classes. Maybe c contains a reference to several Gb of XML. By setting it to null this allows it to be garbage collected before DoSomethingElse is called, which could make an enormous difference. The CLR should perform liveness analysis on c and eliminate the need to set it to null, but if this was a field then it can't do this.
5. If an object supports IDisposable, it means that it owns unmanaged resources either directly or indirectly.
This is wrong. Take IEnumeratorT. This derives from IDisposable. Just because something can be enumerated over does not mean that enumerating it will require unmanaged resources!
Oliver Hallam on January 15, 2009 7:08 AMNow come on Jeff I have just had to read through all the posts, to confirm you don't need sqlConnection = null;. Seems so, hopefully correct as I have never used that line.
pete on January 15, 2009 7:10 AMAssociated with this topic is that people should be reminded that they technically should still call the 'close' function on an object (as well as dispose).. technically the disposable contract doesn't state anything regarding ensuring closing of the object.. whilst most dispose methods do, they are specified not to throw an exception if the object is already closed / disposed..
so you should always do
using(var disposable = .. create disposable ..)
{
.. do your thing ..
disposable.Close(); // -- Or whatever the 'close' method of the type is.
}
For me explicit disposal is probably most important when working on file streams.
Stephen Taylor on January 15, 2009 7:11 AMA long time ago, malloc() used to return char *, so casting was necessary. In 1989 the void * pointer type was introduced in ANSI C, and since then, malloc() returns void *.
So don't forget to include stdlib.h and then it doesn't matter if you cast the return of malloc() or not.
But if you do cast it, be aware that it will probably prevent the compiler from warning you assignment from incompatible pointer type, as it will assume that you know what you are doing.
Thus, the recommended usage is generally:
#include stdlib.h
double *b1;
b1 = malloc(m * sizeof(double));
This is even better, as you don't have to worry if the type of the pointer changes:
#include stdlib.h
double *b1;
b1 = malloc(m * sizeof *b1);
Note that casting the return of malloc() is required in C++ however.
What's that sound I hear? Is it the sound of Comp Sci grads who learned C/C++ in school gathering their pitchforks and torches?
Vance on January 15, 2009 7:12 AM@Oliver: In your example (which won't even compile) the variable C goes out of scope when the using block ends, freeing itself for garbage collection.
mq on January 15, 2009 7:14 AMJeff, you still have to alloc the bl variable:
Double bl = new Double();
@mq
I added that using as an afterthought. Please pretend the first two lines read:
var c = new Class()
using (c)
My point then still stands.
Oliver Hallam on January 15, 2009 7:21 AMI don't like the oh let the computer deal with it attitude. This doesn't mean I like messing around with pointers either, but there you go.
I like the C++ RIAA model -- allocate containers on the stack if you
like, knowing full-well that their constructor/destructor semantics
will keep things tidy.
The finest GC experience I've ever had is with the Qt framework. I wouldn't want to develop a graphical application with anything else. You can write statemets such as
(new SomeQtDerivedWindow())-foo();
SomeQtDerivedWindow bar;
and trust that both will delete themselves when it's time.
I strongly dislike GC being a part of the language a priori, C++ has a no overhead policy for unused features and that's the way it should be. The geniuses who wrote Qt designed a memory management system THAT WORKS IN THAT CONTEXT.
Other types of program might require different memory ownership rules. I despise Java's lack of a predictable out-of-scope destructor -- do people not realise that the lifetime of a variable has meaning in and of itself?
The database example is a good RIAA example. Allocate the object on
the stack and let its destructor close the connection. The object should therefore go out of scope as soon as possible to be efficient, but ISN'T THAT WHAT YOU WANT TO DO ANYWAY? Isn't it good design to not have extraneous variables remaining defined beyond their use?
We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. - Knuth
julio on January 15, 2009 7:31 AMMehrdad: The garbage collector is male?! How come it's not female?
Because then the garbage collector would get to keep half your stuff.
The art of mallocing and freeing is still *pretty* important for a lot of applications.
Agree, which is why I said it can be a pretty important optimization -- depending on the situation, obviously.
The point of this post is the strange tension between auto-GC, which works very well 99% of the time, and the 1% of the time you actually need to care *when and how* resources are released.
Oh, and figuring out when you're in that 1%.
Jeff Atwood on January 15, 2009 7:37 AMThe problem is that we keep repeating our resource handling code all over the place and mixing it with business logic, queries and mostly everything under the sun.
As a programmer, sometimes the very best medicine is a few passionate methods or messages in code. I wrote a TCP and UDP based service that was terminated by sending a MurderDeathKill string as a request. It always felt good.
Blake Schwendiman on January 15, 2009 7:40 AMb1 = (double *)malloc(m*sizeof(double));
Casting the return value of malloc (in C) is not required and hides faults.
foo on January 15, 2009 7:43 AMit's good practice to clean up after yourself. anything less, is a sure mark of a jackass.
ep10 on January 15, 2009 7:45 AMI actually like the extension method. =)
I agree, however, that generally, people don't know how to dispose properly of resources that need disposing. I find it to be one of a number of misconceptions around disposing of resources in general that many programmers face.
Add to that the fact that the guideline for implementing IDispose is wrong in some ways (IMO, I lay out my case here http://www.caspershouse.com/post/A-Better-Implementation-Pattern-for-IDisposable.aspx) and it makes for a total crap-fest.
Basically, it comes to this (this is all in relation to .NET):
- Always call Dispose on IDisposable implementations when done (even if you know the implementation doesn't require it, it's an implementation detail, so yes, MemoryStreams have Dispose called on them).
- Don't bother to set references to null, in release mode (in .NET), you actually increase the lifespan of the reference.
- Call Close when you want to reopen a resource, Dispose when the resource is no longer needed.
- Throw an exception in the finalizer for objects that implement IDispose (see blog entry for more details).
Oh, and your analogy between the managed and unmanaged code equivalent is incorrect, as you can easily declare a double on the stack in C/C++.
Nicholas Paldino on January 15, 2009 7:55 AMLetting the computer deal with it for you might work sometimes, but it makes programmers 'soft.' If you don't understand the intricacies of memory management, pointer manipulation and cleaning up after yourself, you will NEVER BE A STELLAR PROGRAMMER.
I'm sure people can provide a counter-example to the above. Like, oh, I don't know how memory allocation works but I can write a Perl module that proves that creationism is false, but I say bollocks to that -- and I'm not even British. You might be able to do that, but think of how much better you'd be at it if you REALLY understood what was going on.
You can't be a really good programmer without having a solid grasp of what's really going on under the covers. I'm not suggesting that you understand how the electrons flow, but I am suggesting that you form a really solid understanding of how memory works or about bitwise operations.
Garbage collection has coddled us. We've gotten very hand-wavey about things. Oh, let the GC handle it is not good enough. Sure, you might be able to write some decent software and never worry about it, but you SHOULD know about it. You should understand your craft. You should understand that for certain applications, a garbage collected language will NEVER DO. You should be flexible enough to read parts of the Linux kernel (as an example) and grasp what's going on.
Understanding malloc and free -- and understanding what happens when you call those functions -- will never hurt you. Knowing a language that won't patronize or coddle you will NEVER hurt you. And now I'm going to end with a sweeping generalization that will scandalize the masses and begin an epic flamewar:
If you grok C, you'll rock harder than anyone else that doesn't - no matter what language you're currently working in.
Free Memory on January 15, 2009 8:04 AM Oh, and figuring out when you're in that 1%.
Thats why I like doing it manually, you never really know what the garbage collector is doing, and what you don't know can be dangerous.
About the setting the pointers to null after disposing/freeing them, It can be a debugging technique:
if some code touches that pointer later, then you will get a nice clean null pointer exception. If you just leave it as it is, then its still technically pointing at valid data and the code might work, until more memory is allocated on top of it and you get corruption.
But its practically useless, because it won't cross functions unless you use globals. I recommend valgrind instead.
Scott Mansell on January 15, 2009 8:10 AMJeff,
You quoted Aristotle on this blog, you know the quote about success being a habit that has to be built. Cleaning up after yourself builds a habit of not only writing rock-solid code, but it also builds a habit of not using more memory than needed for any given task.
GC is definitely useful but it is non-deterministic. Just think of all pointless discussions about Dispose and Finalize in .NET. What is Finalize good for? Introducing a delay before cleaning up an object that is no longer needed?
Coding without knowing how to manage memory (and other resources) is exactly what lies at the root of the 25 programming mistakes you wrote the other day.
BugFree on January 15, 2009 8:16 AM@Oliver: You're right, it would do something then. However, the intention of the using statement is to create blocks like your first example that help do it automatically with scope. If C needs to be disposed when you're done with it, there's no reason not to declare it in the using block header.
mq on January 15, 2009 8:17 AManonymous: malloc() returns void*. In C, assigning this to another type (technically the void type isn't really compatible with other types) this will result in a compiler warning. It's an error in C++.
reed on January 15, 2009 8:25 AMI think I'd like sqlConn.TakeOutBackAndShoot() better than sqlConn.DieYouGravySuckingPigDog()
But maybe that's just me...
Telos on January 15, 2009 8:35 AMBrad Abrams at Microsoft once answered this question for me, via Scott Guthrie:
Yes, it is a bit confusing…. Dispose() is implemented because SqlConnection implements IDisposable such that it works correctly in C#’s using statement. We also added Close because there is such a strong prior art to using that name. But these methods are suppose to do the exact same thing.
See the guidelines here:
http://msdn2.microsoft.com/en-us/library/b1yfkh5e.aspx
HardCode on January 15, 2009 8:48 AMI'd wager the majority of programmers alive today have never once worried about malloc().
That is a double-edged sword. In the one hand, it is good because of all that bull you just said.
On the other hand, it leads to a complete unawareness of what you are actually doing when you create some system-hogging resource. Many young programmers today write programs as if memory is infinite, and I think the primary reason they do that is because they don't understand that creating an object actually does anything. It may be fine to do that in business where there's a possibility of throwing more hardware at it, but it is a true coding horror in consumer applications, where it may be impossible to do that. Lest we forget - Word 6
Jasmine on January 15, 2009 9:10 AMWow, what a lame site.
When it comes to non-trivial applications, well written C/C++ is still an order of magnitude better (as in faster execution and easier to understand) than well written C#/Python/Java/Ruby/etc. Bad programmers (*cough* JWZ *cough*) who don't understand how to use the tools they are provided will produce bad code no matter what the language. This post is an excellent example of why you should not take what you read on the internet by self-styled experts at face value. Hint to the clueless: even in plain 30 year old ANSI C, you can declare a double that will automatically clean itself up when you are finished with it. If you are as l33t as you think you are, you should be able to figure out how fairly quickly.
Sad Coder on January 15, 2009 9:12 AMPersonally, I rather like pure reference-counted garbage collection systems like Perl uses. Once the object's reference count hits zero, it is immediately destroyed, no waiting around for the GC to do its thing while your program leaks handles or whatever. Granted, you have to be more careful when dealing with circular references, but in practice (at least for me) that doesn't tend to come up as often.
Jim on January 15, 2009 9:16 AMJeff,
Great post! I love the humor in this one, I have to say that I have once in a while taken it out back and shot it with SQL connections. Cause the mistrusting, insecure, inner dev-child in me cannot let GC have all the fun...I commonly refer to it as my Office Space Fax Machine Field Basher method, or in code overload terms myObject.OSFMFB();
Thanks again for the great post!
TexasCoder on January 15, 2009 9:22 AMYou're not disposing your objects? That's a really bad idea, Jeff, I've seen that approach in action on a high-volume ecommerce site. It's not pretty.
But why take my word for it? If StackOverflow is taking this approach, I think you'll see it soon enough (if you haven't already).
dave on January 15, 2009 9:24 AMMost of the Java people I've seen use calls to System.gc() usually didn't have a faint clue what was the cause of their problems. Calling gc was, to them, a wave of the magical Java code-healing wand.
For more info on proper nulling out of objects, see: Effective Java 2nd Edition by Joshua Bloch, Item 6 : Eliminate obsolete object references
Nulling out object references should be the exception rather than the norm, but is sometimes necessary.
Cheers,
e
@Sad Coder:
void super_magic_self_cleaning_double()
{
double d = 0;
// do stuff.
}
:)
Tongue-in-cheek, of course, but locally scoped variables created on the stack get cleaned up after you leave the scope they're created in. :)
Free Memory on January 15, 2009 9:26 AMThe double closing of the connection is silly but setting objects to null after using them is generally good practice. I have seen quite a few memory leaks disappear after doing so.
Practicality on January 15, 2009 9:42 AMAll of which just goes to show that memory is *only one kind of resource*, and that accordingly GC is no magic fairie dust.
And topical, as I have just today been jumping through those stupid hoops that Java makes you go through to tidy up database connections, prepared statements and the like. Grrrr.
Pig dog? PIG DOG??
Charles on January 15, 2009 9:49 AM@Sad Coder
I'm hard pressed to find a reason to use a low level language to enhance the speed of my financial app to the point it would make an iota of difference to the end user. C easier to read and understand than C#. In many cases of code that I've reviewed, open source and in practice I find this hard to beleive.
At what point will it become acceptable to use the proper tool for the job you are doing without religious brow beating.
osp70 on January 15, 2009 9:58 AMJeff, I'm surprised to find out that you are confused about IDisposable.
I suggest you read the comment Aaron G on January 15, 2009 06:39 AM to learn the must-know basics.
@Aaron G: setting a reference to null makes the object eligible for garbage collection.
vitule on January 15, 2009 9:58 AMOh bravo for citing Steve Martin. I loaded this page an hour and a half ago but didn't read it. In the interim my subconscious churned up the Steve Martin bit and I wondered for a while if that was the source, and if I should comment on it. Then I wondered if Steve Martin was really the source (I was exercising, the mind wonders...)
Then I read the comments and you did the name-check for me! Well done!
I may have an unhealthy fascination w/ Martin's old albums. I once sought out Darby Conley's email (the guy who write the comic strip Get Fuzzy) to congratulate him on his beautiful inclusion of may I mambo dog-face through the banana patch in a strip. Never heard back oddly =)
jj33 on January 15, 2009 10:04 AMsqlConnection.Close();
sqlConnection.Dispose();
sqlConnection = null;
All that code example shows is the dev didn't RTFM. The MSDN is pretty clear on how to use the SqlConnection correctly.
If the SqlConnection goes out of scope, it won't be closed. Therefore, you must explicitly close the connection by calling Close or Dispose. Close and Dispose are functionally equivalent. If the connection pooling value Pooling is set to true or yes, the underlying connection is returned back to the connection pool. On the other hand, if Pooling is set to false or no, the underlying connection to the server is actually closed.
And the code example is even better showing the class in a using statement. Really if a dev can't be skillful enough to find out how to use a class properly they shouldn't be writing code.
monkey on January 15, 2009 10:05 AMAaron G is right, as is Ronald with his good advice on the using clause. If a class implements IDisposable, it is YOUR responsibility to dispose of it. Using() does this for you, as does a good IoC container (as Ryan Roberts points out).
The GC is all about MEMORY management. The IDisposable pattern is about RESOURCE management (in particular, unmanaged resources).
See
http://www.bluebytesoftware.com/blog/PermaLink.aspx?guid=88e62cdf-5919-4ac7-bc33-20c06ae539ae
and
http://msdn.microsoft.com/en-us/magazine/cc163392.aspx?ppud=4
And be sure to buy a copy of Framework Design Guidelines (Cwalina and Abrams). It discusses how to implement the Dispose Pattern correctly in detail.
I love your blog, Jeff, but you're off on this one.
Bill Sorensen on January 15, 2009 10:06 AMC:
b1 = (double *)malloc(m*sizeof(double));
C:
double b1;
Dave Parker on January 15, 2009 10:19 AMMore developers need to take some time to read the following chapter: Improved Managed Code Performance
http://msdn.microsoft.com/en-us/library/ms998547.aspx
It would clear a lot of the misconceptions up -- Dispose pattern, when to explicitly set something to null, etc.
Too much good and bad advice being passed around here. Problem is too many people can't tell the difference.
James on January 15, 2009 10:21 AM+1 Ronald... beat me to it.
Steve-O on January 15, 2009 10:26 AMPretty awesome, right? I'd wager the majority of programmers alive today have never once worried about malloc(). I call this progress..
I call it an excuse to write even-more-comupting-power-sucking-applications.
Lets make bigger and havier apps - people will buy more RAM and faster CPUs. Hey, the last time I checked the price of the computer memory it was not as its price in gold. Coder time spent is more precious than performance of the coded product.
Why bother learning malloc and pointers - there is a garbage collector to *collect* the *garbage* left behind the coder.
Release the resource as soon as I'm done is such an important
idiom that Python has built it into the language twice. First
was the try/finally block.
f = open(file)
try:
...
finally:
f.close()
Then starting in 2.5, we have the with statement.
with open(file) as f:
...
I would think that if you needed the resources returned you would want to be able to tell the GC code to go ahead and run and make sure you deal with the resource ASAP:
sqlConnection.Close;
GC.Collect;
Casting the return value of malloc in C works unless:
1) You forget to #include stdlib.h or another header that declares malloc (malloc.h comes to mind for some reason)
2) The size of an integer on your architecture is different from the size of a pointer. Specifically, if sizeof(int) != sizeof(void*).
The reason both of these conditions are necessary is that functions in C that are used but not declared are implicitly declared to return int. This is not a problem on your run of the mill 32-bit intel processor, but there are architectures where the code will cause problems that are difficult to diagnose.
You may note that the posters disgruntled about the cast are likely the ones who cast thrown-away return values to void (so lint doesn't complain) and compile using -ansi -pedantic -Wall -Werror just to prove they're better than you.
Peter on January 15, 2009 11:21 AMThe comments to this entry are closed.
|
|
Traffic Stats |