Take out the trash! When it's applied to computer languages, that command conjures up a different meaning than the one you're used to. In Java, trash, or garbage, is heap memory that a program allocates for objects but no longer references; such memory serves no useful purpose. Just as real-world garbage clogs a trash bin, as Java's garbage piles up, it reduces the total amount of heap memory. If the JVM does not remove that garbage, the JVM eventually runs out of heap memory and can't fulfill future program requests to allocate memory for new objects. To prevent that from happening, the JVM takes out the trash through its use of garbage collection.
In this article, I introduce you to garbage collection, a term computer developers commonly use to refer to memory recycling -- that is, the reuse of heap memory. After learning important details about garbage collection and its various algorithms, you'll learn the practical side of garbage collection from Java's perspective: how to ask the JVM to run the garbage collector, how to finalize objects, and how to resurrect finalized objects (and why that is a no-no!). We start exploring garbage collection by defining that term.
Read the whole series on garbage collection:
- Part 1. Java recycles its memory through garbage collection
- Part 2. The Reference Objects API allows programs to interact with the garbage collector
What is garbage collection?
From a source code perspective, you use the keyword
new to create an object. After you compile that source code into a classfile, the JVM eventually encounters an equivalent byte code instruction to create that object and initialize the object's instance fields to default values. If the object is a nonarray object, such as a single
String object, the JVM executes a
new byte code instruction to allocate memory for that object in the JVM's object heap, a pool of JVM memory that stores objects. However, if the object is an array object, the JVM executes one of the
multianewarray byte code instructions to perform the same tasks. In any case, the JVM reserves memory for the new object in its object heap. As long as that object exists, the JVM does not give that memory to some other object.
|Java's garbage collection activity is JVM-specific. As a result, the output from various programs that appear in this article will not necessarily match your output. Keep that in mind when you start reading the section entitled "Run Java's Garbage Collector."|
Each of the aforementioned byte code instructions returns a reference to the just-allocated memory chunk. That reference might be a C++-style pointer or some arbitrary value identifying that memory. What constitutes the reference depends on the JVM implementation; you do not need to know about it for the purposes of this discussion.
Typically, you assign the just-returned reference to some kind of reference variable whose type is either the same as or similar to the type of the just-created object. Alternatively, you might create a temporary object (making it temporary by not assigning its reference to any reference variable) to call one of that object's methods. For example, you might execute the following code fragment to print a circle's area by first creating a
Circle object with (10.0, 10.0) as the center and 25.0 as the radius, and then calling
area() method via the newly returned reference:
System.out.println ("Area = " + new Circle (10.0, 10.0, 25.0).area ());
The code fragment creates a
Circle object, calls its constructor to initialize that object to a specific center and radius, returns a
Circle reference, and uses that reference to call
area() method, whose return value subsequently prints. After
area() returns, the
Circle's reference disappears from the program. That is why
Circle is known as a temporary object; without the reference, you can no longer call that object's instance methods.
What happens to an object when you lose its reference? In a language like C++, you have just tied up heap memory. Without the object's reference, that memory remains occupied until the program exits. In Java, however, the reference becomes eligible for garbage collection -- the process by which some executable, such as the JVM, automatically frees an object's memory when a single reference to that memory no longer exists.
When a Java program runs, a portion of most JVMs known as the garbage collector runs as a background thread to perform garbage collection. Because that thread runs occasionally at nondeterministic times, you do not know when it will run. (I will cover threads in a future article.)
To carry out garbage collection, the garbage collector thread performs at least the first of the following two main tasks:
- It frees an object's heap memory for later use by a subsequently created object. After all, heap memory is not infinite, and a moment comes when the JVM either needs to free object memory or shut down because all available heap memory has run out.
- It defragments the heap. As the JVM creates objects and its garbage collector frees the memory of unreferenced objects, the heap fragments. Free memory holes appear among blocks of memory assigned to objects. When the JVM attempts to create a new object, enough free memory, from the sum total of all holes, might be available to accommodate the object. However, there might not be a free memory hole large enough to hold the object's instance fields. Defragmentation moves all occupied objects' memory to one end of the heap. That memory serves as one large hole that the JVM can use to allocate memory for new objects.