Table of Contents
In C++, objects are destroyed using class destructors
- If a C++ object has been allocated using the new operator, it is the programmer’s responsibility to remember to clean it up, using the delete operator. (In C++, you can allocate objects on the run-time stack, or in static space, in addition to from the heap.)
- Memory allocation is a very error-prone business in C and C++ — memory leaks are a constant source of problems, and are very hard to find and fix.
In Java, objects are destroyed automatically using a process called garbage collection
- There is no delete operator, as in C++.
- There is no free function or method, as in C.
- The Java garbage collector runs in a low-priority thread, so garbage collection takes place when nothing else is happening.
In Java, an object becomes available for garbage collection when the number of references to that object drops to zero.
For example:
{
Car[] carArray = new Car[10];
for (int i = 0; i < 10; i++)
carArray[i] = new Car();
process(carArray);
// Do more stuff
// carArray, etc., becomes eligible
// for garbage collection when it goes out of scope
}
Or, you can give the garbage collector a chance to get rid of an instance earlier, if you know you won’t need the instance again:
{
Car[] carArray = new Car[10];
for (int i = 0; i < 10; i++)
carArray[i] = new Car();
process(carArray);
// Don't need carArray any more
carArray = null; // eligible for garbage
// collection here
// Do more stuff
}
You can even ‘suggest’ that garbage collection be done:
System.gc();
Note: ‘gc’ is ‘garbage collector’. It’s very rarely used.
In Java, unlike in C++, there are no class destructors. You don’t need them in Java, since allocated memory is cleaned up for you by the garbage collector. (There are situations when you can still get memory leaks, but it’s much less of a problem than in C/C++, and Java’s solution is different — there are no destructors in Java.)
Finalizers and finally blocks
It’s true that, in Java, you usually don’t need a class destructor, because allocated memory is automatically de-allocated by the Java garbage collector. However, sometimes you need to free up a different kind of resource — for example, file descriptors, GUI Windows, database handles, or network sockets, etc.
It is possible to write a finalize method for the class:
protected void finalize() throws Throwable
{ /* ... */ }
which on the surface sounds like a kind of destructor.
In fact, using finalizers is usually more grief than it’s worth. Why?
- The time of instance garbage collection is not deterministic.
- It’s done in a separate, low-priority thread.
- In fact, depending on the program and the platform, the instance may never be destroyed!
- Even if the instance does get garbage collected, this is done in a separate thread, and can (and often does) raise serious synchronization problems and can cause deadlocks. These are very tricky to debug, and hard to fix, even once you’ve found the problem.
- In short, don’t use a finalizer where you would use a destructor in C++.
- In fact, in most cases, don’t use a finalizer at all!
Instead, what is typically done to reliably release resources in Java is to use a finally block:
// Allocate resource here.
try
{
// Use resource here
}
finally
{
// Release resource here
}
By placing the code to release a resource in a finally block, you ensure that it will get executed whether the code runs successfully, or whether it throws an exception.
Note: There is a similar problem with releasing resources in C++, when exceptions are thrown:
/* C++ code */ Resource rsc = new Resource() // ... // <code that uses the resource, // potentially throwing an exception> // ... delete rsc; // Only executes if no exception is thrown
