Casting the return value of malloc in C works unless:
You forget to #include stdlib.h or another header that declares malloc (malloc.h comes to mind for some reason)
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.
I’m in the camp that it’s not really an optimization if it helps your application function correctly 100% of the time.
Why bother avoiding the inevitable? Why skip this simple step if it will save you time and $$$ later?
It’s like home owners insurance (provided you don’t live in a disaster prone area). You’re about 99% sure nothing bad is going to happen to the home…and yet you still own the insurance policy, right?
I could go on about the issues I’ve seen but let’s just say that the guidance is there for a reason.
While calling Dispose() or implement the using… pattern might not have a noticeable impact to your application today (with 5 users) - that is not to say that it won’t when traffic increases or you add additional functionality.
I should probably also mention that while garbage collection works for general applications, it’s no magic bullet. Try using it in real-time systems, and you will surely encounter some problems. Why aren’t your brakes working?! – Oh, it’s probably just the garbage collector running again… just give them a minute.
Jeff, I know you don’t know C and I certainly don’t see anything wrong with that, but if you are going to write about it at least bother to do it with some rigor. Your C example is for allocating a memory block on the heap capable of holding m double values. Your C# example is for declaring Double value on the stack. So you are comparing an array on the heap vs. a value on the stack. You couldn’t have mixed up your examples more than that.
Here’s an example of a value on the stack in C:
double b1;
And since this is on the stack there is nothing to clean up afterward.
Here’s an example of an array of m doubles in C#:
Double[] b1 = new Double[m];
Obviously, C programmer has to use free() to clean up after the allocation, C# programmer can relax about all that due to GC.
No comments on the article, but Jeff, can you avoid linking to yourself in the quotations that you use? Yes, Worse is Better is hyperlinked in the original text. But not to the URL that you linked to. As it is now, it looks asi if JZ linked to your blog post of January 30, 2008 when he wrote the article on Februrary 1, 1998
I think that not enough attention is paid to this concept (granted that in most situations it is not that serious) and I think that is is due partly to the fact that many times it does not show up until some stress testing is done.
The example I give is an application that we have did multiple complex multi step runs. When each run started, lots of things were allocated, during the run things got bigger and more things allocated and at the end of the run not everything got released. This was mostly hidden because the memory usage went up and down a lot during a run (20 MB - 100 MB).
Trying to find out which object was hanging around was the problem. Once we figured out which object was not getting released, it was easy to figure out why (the object genereated events and there was still one listener subscribed).
Relying solely on GC in .NET is not always be the best choice.
Also, do not confuse the example in this post (Connections) with disposing of data structures. Closing a connection immediately returns it to the pool; Disposing and setting it to Null to regain a few bytes perhaps not quite so important.
Immediately recapturing data from sizable structures is probably wise. The GC has been proven to be laxidasical on occasion.
GC only solves half of the memory management issues. You still need to be careful or you will cause memory leaks from dangling references. In a complex application they can be really difficult to track down.
The real problem in your example of the close/dispose/null is the developer simply not understanding the dispose pattern in .net. .Close() and .Dispose() do the same thing (Dispose() actually calls Close()). Setting the variable to NULL doesn’t really do anything.
I’d wager the majority of programmers alive today have never once worried about malloc(). I call this progress.
I would disagree. I am totally in favor of using high-level languages, and the widespread acceptance of automated memory management is a good thing. However, the fact that the majority of programmers alive today have never done any low-level programming means that they really have no idea how a computer works. This is not progress.
My Disposable class contains debug code to find common IDisposable bugs, such as leaked objects that have not been disposed and classes whose override void Dispose(bool disposing) forgot to call base.Dispose(disposing).
You can copy and paste my Disposable class as a boilerplate for your classes that implement IDisposable.
IDisposable is contagious: if a class has any IDisposable member variables, it should be IDisposable and dispose of its member variables. This abstraction leak can require some unexpected classes to be IDisposable because some of their private member variables are IDisposable.
Better yet, if your class does not derive from any base classes, you can derive from my Disposable class. Your class just needs to override void Dispose(bool disposing), cleanup your managed resources (i.e. dispose of your IDisposable member variables), and call base.Dispose(disposing).
If your class (like 99% of all classes) does not contain any unmanaged resources, there is no reason to define a finalizer. There is nothing your finalizer can do! Your finalizer is not allowed to touch any (managed code) member variables because (surprisingly) they might have already been finalized. You can’t even call Dispose() on your IDisposable member variables.
Except for the title, I don’t see the point of this blog entry.
1/2 the programmers alive have never used malloc()? What a rubbish statement to make. I seriously hope that nearly 100% of programmers have used C or C++ at least once in their life.
Although I no longer program in C, knowing C means I know how my computer works.
IDisposable is for the necessary case of having deterministic disposal, and is a compiler supported feature to make simple cases quite simple (via the using keyword). It’s somewhat trivial to use, and not so trivial to implement correctly, but nobody said everything was easy.
As much as you may wish otherwise, your computer doesn’t have unlimited resources. You don’t need to be a nazi about it, but you do need to be cognizant of it.
fyi @punters
you should never call GC.Collect() - I’m not even going to go into this one.
.net does have pooled connections (configured by the provier). That still doesn’t mean you don’t release a limited resource as quickly as possible to have an efficient pool.
I love having a gc, because I focus on the program and not low level malloc()'s
you do not call GC.Collect() after calling sqlConnection.Close(). Close() releases any of the unmanaged resources and (probably) informs the runtime that the class no longer needs finalizing. All that is left can be reclaimed by the GC in it’s normal course of duty.
Blog comments are really not the place to go through .Net memory management, IDisposable, and finalizers.
Jeff in this artical, you quote somebody who hyperlinks Worse is Better by Richard Gabriel. However in your quote you change the hyperlink the Worse is Better by Jeff Atwood.
That is a misquote of the original and I call you.
You have a great blog, and I enjoy reading it very much, but you must have integrity when you quote somebody.
When quoting you can’t change the hyperlinks they use or insert extra hyperlinks to your own work, any more than you can change the meaning of what they said by missing out the odd word here and there.
This article is wrong (and dangerously misleading). Failure to dispose IDisposable objects is a real error, and can easily cause nondeterministic crashes and deadlocks.
For example, opening a log file and writing a line and forgetting to close it means the next time you try and open+write your program might crash (file locked) - or it might not, if the file stream was garbage collected.
If you open a DB connection and fail to dispose, you may or may not run out of connection pool connections, depending on memory load and pool size. It won’t be easy to reproduce, anyhow.
If you open a database streaming reader and fail to close it, all subsequent sql commands on that connection will throw a connection error - unless the reader was collected.
If you open a transaction and fail to dispose it, subsequent transaction-aware commands will jointly succeed or fail - possibly changing semantics (though almost certainly just throwing an exception, eventually).
The permissiveness of C# when it comes to IDisposable objects is perhaps its #1 design flaw. It’s almost always an error if an IDisposable is not used within a using or an equivalent try…finally block.
Garbage collection is good; it doesn’t make resource management irrelevant.
As a programmer I like to have as much about my program as possible. Garbage Collection (GC) takes a large amount of control away from me. It is very convenient to use (don’t care about memory), but it means I have pretty much no control how much memory my application will use at what time (since the GC will run whenever it wants to run, dumping an object does not give me the memory of it at once - it may not even give me that memory 30 seconds later). Further every GC run takes CPU time, so I cannot know when my app will use how much CPU time to perform operations, since GC operations are performed in the background at any time the system decides to do so.
You may not care for such kind of issues in high level languages like PHP, but the kind of applications usually written in C are written in C because it is hard to make them run faster or use less memory when writing them in any other language (maybe when you write them in pure assembly, but that’s it) - and here these are important aspects. A C GC is only useful if:
I can stop it at any time, so I can make sure it will not run within a performance critical section
I can force it to free up a memory block right now, because I need this memory back right now (and not any time in the future)
However a GC working like this will hardly show much advantage over manual memory management. Actual manual memory management has no real disadvantages to begin with. The only disadvantage is that you must remember to free memory at some place and at some time. And this is not really a disadvantage of the memory management itself, the disadvantage comes from the fact that human beings are imperfect and do stupid things like never freeing memory again or freeing it too early when it is still in use - so the main task of a GC is to do something for you that you could also do yourself, but for that you might be too stupid to do it right.
Regarding issues like Yes, but it also saves me of writing more code. You are not really arguing about this tiny free statement, are you? Despite that, for throwaway objects you can write yourself convenience functions, like release pools.
int blahblah (…) {
int result;
ReleasePool p = createReleasePool();
…
…
void * memblock = automalloc(2000 * sizeof(double), p);
…
…
int * intpointer = automalloc(sizeof(int), p);
…
…
releasePool§;
return result;
}
automalloc does a normal malloc and stores the malloc result internally into the pool p, then it returns it.
Right before you are done with a huge function, creating plenty of small temporary objects, you release the pool itself, which means it will once run over all stored pointers and call a free on them. This way you don’t have to write hundreds of free at the end of the function.