job. To that end, we'll present a series of antipatterns involving memory leaks.
Finally, we'll look at tools and techniques that will help us solve memory leaks.
In any object-oriented language, each variable, regardless of scope, must be
allocated. In most cases, memory can come from three primary sources: regis-
ters, the stack, and the heap. The compiler (or interpreter) closely manages
registers and the stack, so we'll focus on the heap. We can think of the heap as
a mailbox with different-sized slots. A compiler or interpreter will have a
memory manager, analogous to a postmaster, to manage these slots. Imple-
mentations of memory managers can vary widely, from single runtime entities
to static libraries. It's the manager's job to configure the size of the slots, allo-
cate them as needed, and reclaim them for later use. For some low-level lan-
guages, like C++, the manager is a very thin layer. The programmer is
responsible for explicitly requesting a block of memory (with new or malloc )
and explicitly freeing the block (with free ) when it's no longer required. C ++
also forces the programmer to track individual addresses of memory blocks
through pointers . This implementation makes C++ very flexible, but also
tedious and problematic. Table 6.1 shows some of the bugs that a C ++ pro-
grammer might encounter. We'll focus on the dangling pointer and the mem-
ory leak, because both are realized differently in Java.
Table 6.1 Problems encountered while managing memory in C++. The third column shows the
types of program failure that you can expect.
Memory is allocated.
Memory is not freed.
This is the classic memory leak. The pro-
gram grows indefinitely, slows as free mem-
ory runs out, and eventually fails with an
Memory is freed with no
The program fails with a free error.
Memory is freed, but the
pointers not updated.
As lists, trees, or other structures are tra-
versed, the program crashes with unpredict-
Invalid pointer; lost
Pointers to valid memory
addresses are overwritten.
The program crashes.