right now. That is, no method or class exists to let you specifically collect an existing object. You may be
sure that the object can safely be removed, but you can't force the garbage collector to remove it.
This lack of control drives plenty of software developers a little nuts. As a group, software developers
tend to want to control the computers they program, so a system that offers only indirect control is often
not welcomed. For programmers accustomed to other languages (especially C++), that's often a primary
complaint when they start using Java. Rather than have direct control, Java developers must instead be
careful not to allow unnecessary references to exist.
When Java was new, some developers thought and said nonsense such as, “Oh, great! Java will
manage my memory for me!” Therefore, more than a few programs with an unfortunate tendency to use
large amounts of memory were created as a result. Having a garbage collector doesn't allow us to be lazy.
We still have to manage memory, but we don't do it explicitly.
Another common complaint with Java (and other languages that use garbage collection) used to be
that everything stopped while garbage collection ran. The addition of incremental and concurrent
garbage collection has reduced that complaint somewhat, and further refinements in Java's garbage
collection algorithms have improved the situation greatly. It used to be common for Java programs to
have long pauses when the garbage collector ran. With the modern Java virtual machines available now,
those pauses are now very rare (and are a symptom of poor programming rather than the JVM).
The Java garbage collector uses the concept of generations. In most applications, nearly all objects exist
for a very short time. If you look at the Target objects created by an instance of the TargetClickPanel
class (listed in the previous chapter), you'll see that they exist for just a few seconds each. In fact, if a
player clicks on one, an instance of the Target class might exist for only a fraction of a second.
Conversely, the TargetClickPanel instance and the TargetClick instance both exist for the duration of
the game, but there's only instance of each class for the entire time.
Suppose a game of TargetClick involves the creation of 100 Target objects. In that scenario, two
objects (one instance of the TargetClick class and one instance of the TargetClickPanel class) exist for
the entire life of the program, while 100 other objects (all the instances of the Target class) exist for no
more than a few seconds each. So, at least in this case, we have a great example where nearly all objects
are not present in the system for long.
All of these short-lived objects end up in the “young generation.” The young generation has three
spaces: “eden,” “from,” and “to.” The eden space is where objects go first. So, when your program
creates a new object (such as an instance of the Target class in the TargetClick game), the object goes
into the eden space. The from and to spaces are called “survivor spaces,” and objects that survive at least
one garbage collection pass move to these spaces until they've survived sufficiently long to move to the
tenured generation. At any given moment, one survivor space is empty. When the garbage collector
runs, it moves the survivors from the eden space and the currently occupied survivor space into the
currently empty survivor space.
Objects that last a while (either a certain amount of time or a certain number of collections) end up
in the “tenured generation” (also called the “old generation” - the older I get, the more I prefer to talk
about the “tenured generation”). Finally, the “permanent generation” isn't really a generation but is
instead the area where the JVM stores the class definitions. The permanent generation isn't necessarily
static, as Java programs can load and unload classes as they run.