Let's consider a fictional program that builds a linked list in the heap, and at the end of the program there is a loop that frees all the nodes, and then exits. For this case let's say the linked list is just 500K of memory, and no special space managing is required.

Is that a waste of time, because the OS will do that anyway?

Will there be a different behavior later?

Is that different according to the OS version?

I'm mainly interested in UNIX based systems, but any information will be appreciated. I had today my first lesson in OS course and I'm wondering about that now.

Edit: Since a lot of people here are concerned about side effects, and general 'good programming practice' and so. You are right! I agree 100% with your statements. But my question is only hypothetical, I want to know how the OS manages this. So please leave out things like 'finding other bugs when freeing all memory'.

I had a program once that re-sorted a linked list 7 times, and then tried to deallocate it. The sorting took 2 hours, but the deallocation took 4 hours because all the sorting has blown any locality of reference. I sped up my program 200% by leaking the memory :D
–
MSaltersMar 19 '12 at 15:42

1

@MSalters: Assuming C++ or C, you could also have allocated from a (per-list) pool. That would allow you to deallocate all of the nodes in one go, regardless of how they might refer to one another.
–
Jon PurdyMar 19 '12 at 18:58

16 Answers
16

My main problem with your approach is that a leak detection tool (like Valgrind) will report it and you will start ignoring it. Then, some day a real leak may show up, and you'll never notice it because of all the noise.

@Vilx: Any difference in execution between debug and release mode can cause you extremely annoying problems, should something go wrong.
–
David ThornleyMar 19 '12 at 15:34

1

If there is a leak and you never notice it, then it's not a problem. The goal is not to create a perfect program, the goal is to create a program that the end user will like.
–
Andreas BoniniMar 19 '12 at 19:58

1

@fast program vs safe program: does deallocation need so much time? I'd rather think it takes a very small portion of a program's running time.
–
GiorgioMar 21 '12 at 19:48

Once I had to implement an algorithm using deques which were allocated dynamically. I was also wondering whether I needed to deallocate all the allocated data at exit.

I decided to implement the deallocation anyway and found out that the program crashed during deallocation. By analysing the crash, I found an error in the implementation of the main data structure and algorithms (a memory leak).

The lessons I learnt were:

Always implement deallocation for the data you allocate, this makes it more reusable in case you want to embed your code in a larger system.

Deallocation can serve as an additional check that your allocated data is in a consistent state when it is released.

Just my 2 cents.

EDIT

Small clarification: Of course all memory allocated to a process gets released when the process is terminated, so if the only requirement is to release the allocated memory, doing it explicitly is indeed a waste of time.

OK, I just got an Email back from my instructor, with a very good and reasonable answer. Here it is:

Hi Martin,

Thanks for the link to the interesting messages thread which you
started.

As per our discussion, malloc operates on the process' virtual memory.
So, when the process dies, its virtual address space "disappears", and
any physical memory mapped to it is freed. Hence, disregarding "good
software engineering practices" and such, dynamic memory de-allocation
just before exiting a process is indeed a waste of time.

(Needless to say, this is not the case when a single thread terminates
but other threads of that process keep executing.)

@Martin If you are only interested in an OS point of view I think it is off topic. Since you got the answer that you were interested in, maybe you should have selected an answer that was more appropriate for the platform.
–
scarfridgeApr 23 '12 at 19:16

The cleanup routine may be useful if you do it periodically to regain space, or to prove that you are able to reclaim exactly as many nodes as you allocated, to verify that there are no memory leaks. But as housekeeping immediately before the process dies, it makes no sense, since the OS regains control of that entire arena of memory at that instant.

Always free your resources. Freeing all your resources is important because it's the only way of being able to effectively detect leaks. For the project I'm working on I've even got wrappers around malloc/realloc/free to insert canaries, track statistics, etc; simply to detect problems sooner.

However, except for leak detection, for resources that are freed at exit (not before) it is a waste of time. The OS must be able to free it (e.g. in case the process crashes, or even just freeing RAM used for the process' code); and the OS should be able to free it faster than you can from user-space because the kernel will do "wholesale" rather than "piecemeal", and there's less transitions between kernel and process involved.

Fortunately you don't have to choose one way or another. If you want to make sure your code is correct (and you do), but you also want the best possible performance, then do something like:

There is a critical question related to this one that you need to ask:

Will anyone ever use this code ever again for any reason?

If the answer could ever be yes, whether the code is used alone or as a part of a larger system, you have created a monumental memory leaking landmine for the next person to step on.

It is very hard to remember during your coursework that you are learning how to make software that other people are going to use including future-you (rather than just solving the homework problem of the day). This means that you need to abide by certain basic programming behaviors including: give back the resources when you are done with them.

In some languages, freeing resources merely means releasing the pointers to the memory areas... the old data will still be present in memory unless you scrub it first.
–
Robert HarveyMar 19 '12 at 15:37

3

@RobertHarvey: True, but that doesn't matter if you then exit the process. The OS doesn't care which language you used (it's all assembly to the OS anyway) and will scrub the memory regardsless, just to be sure.
–
MSaltersMar 19 '12 at 15:40

Cleanup routines can have bugs just like any other code. A sad sight is a program that does what you want except that it hangs or crashes at exit. General practice is to have code clean up after itself, but memory cleanup at process exit is a case where you don't have to.

The problem is that today it's a linked-list node, and tomorrow, it's a resource the OS can't clean up by itself. Is it fast and safe to leave the OS to clean up heap memory? Yes. But does that make it a good idea? Not necessarily.

If you implement your own data type "linked list" not writing a cleanup routine/deconstructor will give you more headaches in the long run than you might think.

Without cleanup code reusing what you wrote will be much harder since your type cannot be used without taking special care (e.g. never create them in a function or loop, but preferably exclusively in main).

Do yourself and everybody else a favor and just write you list_cleanup or ~List.

Memory isn't shared by multiple processes. Well, it can, but you have to go out of your way to even allocate it.
–
delnanMar 19 '12 at 15:25

2

@JBRWilkinson Copy-On-Write is an optimization, and it's only valid because it has no semantic impact. With or without COW, parent and child process do not affect each other's memory after fork().
–
delnanMar 19 '12 at 17:44

I always clean up resources on normal exit. It's a safety check that my resource allocation/deallocation calls are done right. This check has alerted me to hidden bugs on more than one occasion. It's like balancing the books of a business at the end of the day.

There may be edge cases such as @MSalter described in his comment, but even that would generally start me looking at customized memory management, rather than just letting the OS clean up and hoping for the best.

Some C++ GUI libraries leak resources like this. This is not a value judgement, but leaking resources and letting the OS reclaim them is a somewhat common occurrence in "real code."

It's always good practice to clean up though, you never know when you'll want to integrate that tool with something else, and then the work is already done (instead of going into the wayback/ remembering machine and remembering all the spots you intentionally leaked).

In one case we actually found a bug because the deallocation was causing a crash because some other memory bug had overwritten the header that delete uses. So, sometimes it can actually help you to find bugs in other areas to free all your resources (you can find an overrun in the previous block).

That was not my question. And if you read the answer i got from my instructor, you should see that it has no importance how it stored. The only important thing is the fact that its a process.
–
KahilApr 4 '12 at 15:48