Glossary of terms
- finalization
- A fallback mechanism for cleaning up finite resources. Finalization occurs when the garbage collector calls a resurrectable object's overridden
finalize()method. - 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.
- garbage collector
- That part of the JVM that performs garbage collection.
- handles
- Indexes into a table of object references.
- mark-and-sweep algorithm
- A tracing-based garbage collector algorithm that first marks in some way each object during a trace through all objects on the object heap and then sweeps all unmarked objects into oblivion.
- object heap
- That portion of the JVM's memory area from which the JVM allocates memory for new objects.
- reachable
- A state in which an object can be reached via some path that starts from a root-set variable.
- resurrection
- The act of preventing an object's collection by making it reachable from inside its
finalize()method. - root set of references
- A group of reference variables always accessible to an executing Java program. Those variables include local variables, parameters, and class fields.
- stop-and-copy algorithm
- A copying-based garbage collector algorithm that divides the object heap into an object area and a free space area. The stop-and-copy garbage collector stops program execution while it copies objects from the object area to the free space area, defragmenting the heap in the process.
- Train algorithm
- A modified generational collector algorithm that manages the mature object space to shorten the delay that the garbage collector imposes on a program.
- unreachable
- A state in which an object cannot be reached by any path starting from any root-set variable.
Tips and cautions
These tips and cautions will help you write better programs and save you from agonizing over error messages produced by the compiler.
Tips
- Get into the habit of ending your
finalize()methods withsuper.finalize();method calls. That way, if you insert a superclass above your class and if that superclass has its ownfinalize()method, you can be sure the garbage collector calls superclass'sfinalize()method.
Cautions
- You should call
System.runFinalization ();immediately after a call toSystem.gc ();. If you placeSystem.runFinalization ();beforeSystem.gc ();or omit theSystem.gc ();call, not allfinalize()methods will run. (I do not know the reason for this.) - If you resurrect an object and then make that object unreachable, the next time the garbage collector runs, it will collect that object without calling the object's
finalize()method.
Miscellaneous notes and thoughts
You might be wondering why I did not include instance (that is, object) fields in the root set of references. The reason is that, unlike class fields (which are always accessible through a program's lifetime) and local variables/parameters (which are always accessible during a method call), instance fields become inaccessible to the garbage collector when an object becomes unreachable.
Homework
This month, you have three questions to answer:
- Why is it beneficial that Java, rather than the developer, frees objects?
- Write a program that demonstrates how you can run out of memory in a Java program. What happens when you run out of memory?
- What is a disadvantage to a generational garbage collector? (Hint: Why does the Train algorithm exist?)
Answers to last month's homework
Last month, I asked you to trace the initialization process through the Employees source code below (assume that java Employees starts the program):
Employees.java
// Employees.java
class Employee
{
private String name;
private double salary;
static int count;
static double bonus;
Employee (String name, double salary)
{
this.name = name;
this.salary = salary;
if (this instanceof Accountant)
this.salary += bonus;
}
static
{
// Pretend to load bonus from a database.
bonus = 500.0;
}
{
if (count > 5)
bonus = 0.0;
count++;
}
String getName ()
{
return name;
}
double getSalary ()
{
return salary;
}
}
class Accountant extends Employee
{
Accountant (String name, double salary)
{
super (name, salary);
}
}
class Employees
{
public static void main (String [] args)
{
String [] names =
{
"John Doe",
"Jane Smith",
"Jack Jones",
"Bob Smyth",
"Alice Doe",
"Janet Jones"
};
double [] salaries =
{
40000.0,
50000.0,
30000.0,
37500.0,
52000.0,
47000.0
};
for (int i = 0; i < names.length; i++)
if (i < 3)
{
Employee e = new Employee (names [i], salaries [i]);
System.out.println ("Name = " + e.getName ());
System.out.println ("Salary = " + e.getSalary ());
}
else
{
Accountant a = new Accountant (names [i], salaries [i]);
System.out.println ("Name = " + a.getName ());
System.out.println ("Salary = " + a.getSalary ());
}
}
}
When run, Employees produces the following output:
Name = John Doe Salary = 40000.0 Name = Jane Smith Salary = 50000.0 Name = Jack Jones Salary = 30000.0 Name = Bob Smyth Salary = 38000.0 Name = Alice Doe Salary = 52500.0 Name = Janet Jones Salary = 47500.0
How does Employees achieve that output? The following numbered list takes you through the program's execution and itemizes all initialization steps until the last Accountant object finishes initializing:
- The JVM's class loader loads
Employees.classinto memory, and the JVM's byte code verifier verifies all byte code instructions in that class. - Because class
Employeesdeclares no class fields, the JVM does not allocate memory for class fields and zeroes all bits comprising that memory. - The JVM starts executing
Employees'smain()method. Memory is allocated on the method call stack for local variablesnames,salaries,i,e, anda. - The
main()method's byte code instructions create anamesarray and asalariesarray. References to those arrays (whose memory exists on the JVM's object heap) assign to local variablesnamesandsalaries. - The
forloop statement byte code instructions begin to execute. Zero assigns to local variablei. - Because
i's value (0) is less thannames.length's (6),forexecutes theifdecision statement. ifevaluatesi < 3. Becausei's value (0) is less than 3, the byte code instructions comprisingEmployee e = new Employee (names [i], salaries [i]);start to execute.- The JVM detects the presence of class
Employeein those instructions and has its class loader loadEmployee.class. The JVM's byte code verifier then verifies all byte code instructions comprising that class. - Because class
Employeedeclares two class fields (countandbonus), the JVM allocates memory for those class fields and zeroes all bits comprising that memory. The JVM executes
Employee's<clinit>method. That method assigns500.0tobonus.- The JVM allocates memory for an
Employeeobject'snameandsalaryinstance fields, and zeroes all bits comprising that memory. A reference to that object's memory is placed in a temporary stack location. - The JVM executes the
<init>method corresponding toEmployee(String name, double salary). - The
<init>method first callsObject's no-argument<init>method, which does nothing and subsequently returns. - The
<init>method next executes anifdecision statement's byte code instructions that evaluatecount > 5. Becausecountcurrently contains 0,0.0does not assign tobonus. - The
<init>method next executes the equivalent ofcount++.countnow contains 1. - The
<init>method next assigns the reference in itsnameparameter to thenamefield and the double-precision floating-point value in itssalaryparameter to thesalaryfield. - Finally, the
<init>method uses the byte code equivalent ofinstanceofto see if the current object is an instance ofAccountant. Because the object is not such an instance, nothing further happens and<init>exits. - The JVM takes the
Employeeobject's reference from the temporary stack location and assigns it to local variablee. - The two
System.out.println()method calls result in calls toEmployee'sgetName()andgetSalary()methods for the object referenced bye. Those methods return the appropriate name and salary values, which subsequently print. - The
forloop statement incrementsi(which becomes 1), and checks to see ifi's value is still less thannames.length's (6) -- which it still is. Therefore, theifdecision statement executes a second time. - Because the next two iterations (where
icontains 1 and 2) repeat previous steps, let's continue whereicontains 3. ifevaluatesi < 3. Becausei's value equals 3, the byte code instructions comprisingAccountant a = new Accountant (names [i], salaries [i]);start to execute.- The JVM detects the presence of class
Accountantin those instructions and has its class loader loadAccountant.class. The JVM's byte code verifier then verifies all byte code instructions comprising that class. - Because class
Accountantdeclares no class fields, the JVM does not allocate memory for class fields and zeroes all bits comprising that memory. - Because class
Accountantcontains no class initializers, there is no<clinit>method to execute. - The JVM allocates memory for an
Accountantobject'snameandsalaryinstance fields (which are located in theEmployeelayer), and zeroes all bits comprising that memory. A reference to theAccountantobject is placed in a temporary stack location. - The JVM executes the
<init>method corresponding toAccountant(String name, double salary). - The
<init>method first callsEmployee's two-argument<init>method. Employee's<init>method callsObject's no-argument<init>method, which does nothing and subsequently returns.Employee's<init>method next executes theifdecision statement that evaluatescount > 5. Becausecountcurrently contains 3,0.0does not assign tobonus.Employee's<init>method next executes the equivalent ofcount++.countnow contains 4.Employee's<init>method next assigns the reference in itsnameparameter to thenamefield and the double-precision floating-point value in itssalaryparameter to thesalaryfield.- Finally,
Employee's<init>method uses the byte code equivalent ofinstanceofto see if the current object is an instance ofAccountant. Because the current object is such an instance, the contents ofbonus(500.0) are added to thesalaryfield. Employee's<init>method exits toAccountant's<init>method.Accountant's<init>method has nothing further to do, so it exits.- The JVM takes the
Accountantobject's reference from the temporary stack location and assigns it to local variablea. - The two
System.out.println()method calls result in calls toAccountant's inheritedgetName()andgetSalary()methods for the object referenced bya. Those methods return the appropriate name and salary values, which subsequently print. - The
forloop statement incrementsi(which becomes 4), and checks to see ifi's value is still less thannames.length's (6) -- which it still is. Therefore, theifdecision statement executes a second time. - Because the next two iterations (where
icontains 4 and 5) repeat previous steps, let's continue whereicontains 6. - Now that
icontains 6, theforloop statement, followed bymain(), exits. Beforemain()exits, the JVM releases memory for the local variables from the method call stack.


![JavaWorld > Android Studio for Beginners [movile java package]](https://images.idgesg.net/images/article/2019/02/jw_android_studio_for_beginners_3x2_1200x800_pkg_idg_google_darkovujic_gettyimages-100788152-small.3x2.jpg)
![JavaWorld > Persistence [series] > data blocks / data center / database / server traffic routing](https://images.idgesg.net/images/article/2019/04/jw_java_persistence_series_3x2_2400x1600_3_data_center_database_digital_information_blocks_server_traffic_routing_by_ramcreativ_gettyimages-100792562-small.3x2.jpg)