Tutorial Java – #9 Garbage collection and memory leaks

1 comment - This post in romanian

Since the first days of computer programs, one important performance issue was the and still is the amount of used memory. Despite the fact that today the hardware technology provide large amounts of Random Access Memory, software developers must pay attention to how they manage the application memory because they can implement wrong solutions that will crush the process or the machine because they ran out of memory. In other real applications, you may have some hardware constraints and the maximum amount of available memory can be a strict technical specification.

Other topics that are part of this Java tutorial are accessible through Java 6 Tutorial – Contents.

Garbage collection is directly connected to using Heap memory area because this is the part from RAM where the operating system provides, in a dynamic manner, additional memory space to processes that require it at run-time. In order to get space in Heap and store your values there, you get through a 2 step process:

  • request memory and store the address in a reference/pointer; depending on the programming language you use malloc in C, new in C++ and also new in Java;
  • initialize that area with values using the reference/pointer to access it;

Another concept related to garbage collection is memory leaks. These are situations in which you decrease the amount if available Heap memory by requesting memory zones and not releasing them after you have finished using them. In C and C++ this was a real problem because it was very easy to do it. The next C++ example (even if you don’t have C++ knowledge it is easy to read the example; just assume that the int * pointer is like the int[] reference):

void main()
{
	while(true)
		//generating a 4000 bytes memory leak
		int* array = new int[1000];
}

The previous C++ example is running an infinite loop and in each one of the iterations it is requesting space (in Heap) for a 1000 integer values array. It is obvious that the array it is never used and we loose its Heap address in the next iteration. That is a simple example that generates memory leaks. If you run the example and you check its process in Task Manger (for Windows), you will see that the process memory is increasing until you get low on virtual memory warning or the process is stopped by the OS (depends on your OS).

The correct version of the example (without memory leaks) looks like this:

void main()
{
	while(true)
	{
		//generating a 4000 bytes memory leak
		int* array = new int[1000];
		//release the unused memory
		delete[] array;
	}
}

The same example, written in Java looks like this

public class Main{
	public static void main(String[] args) {
            while(true)
            {
                int[] intArray = new int[1000];
                //space released by the Garbage Collector
            }
	}
}

and for your surprise it will generate memory leaks but the process memory remains at a stable and low level. The reason is that your Java process runs in the Java Virtual Machine which will clean up unused Heap memory with its internal routine called Garbage Collector.

The previous example is a simple one. Despite the fact that you have a Garbage Collector that will watch your back in situations like that, you must pay attention to memory because you are still able (not so easily like in C or C++) to write Java applications that will run out of memory.

Because Java is an OO programming language and because all objects are stored in Heap (remember that they are created using new), we may say that the JVM Garbage Collector finds unreachable objects and reclaims their space back to the available pool of resources. An unreachable object (it is a memory leak) is a Heap zone that can no longer be found/reached using a reference.

How to use Garbage Collector

The Garbage Collector has evolved so much that for the Java 1.6 you know for sure:

  • it uses different methods to manage references and the corresponding Heap addresses; the most trivial method is that is uses a table to count how many references are used to reach a Heap memory zone; when the number of references gets to 0 then the memory zone is released;
  • it is a complex and very efficient JVM routine that will not interfere with your Java process performance;
  • it will not save any out of memory situation (OutOfMemoryException); remember that any live object (it is reachable by a live reference) it is not collected;
  • you can request garbage collector to make a memory clean explicitly by invoking the System.gc( ) method;
  • it is not recommended to interfere with the garbage collector by calling System.gc( ) method, because you have not any guarantees on how it will behave;

How to generate unreachable objects or memory leaks

In order to generate unreachable objects or memory leaks and to enjoy the benefits of having a Garbage Collector you must loose or remove all the references for that object.

1. The simplest way is to null a reference:

public class Main{
	public static void main(String[] args)
        {
            int[] intArray = null;
            //request space in Heap
            intArray = new int[10000];
            //process your data
            //...
            //make the reference null
            //the array values are becoming eligible for GC
            intArray = null;
	}
}

In this way the object becomes eligible for garbage collector because we don’t have any other reference used to reach the object.

2. Reassigning the reference we make the previous object unreachable:

public class Main{
	public static void main(String[] args)
        {
            int[] intArray = null;
            //request space in Heap
            intArray = new int[10000];
            //process your data
            //...
            //create a new object and use  the same reference
            //the previous array values are becoming eligible for GC
            intArray = new int[99];
	}
}

In this way the first object becomes eligible for garbage collector because we don’t have any other reference used to reach the object.
3. Isolating a reference it is a more hidden scenario because at a first glance you may say that your object is still alive. If we consider the next class:

class Student{
    int age;         //instance variable
    int[] marks;     //instance variable
 
    public Student()
    {
        this.age = 0;
        marks = new int[10];
    }
}

you can see that every Student object contains an array reference as an instance variable. If we test the class like this

public class Main{
	public static void main(String[] args)
        {
            Student s = null;
            //request space in Heap
            s = new Student();
            //process your data
            //...
            //remove the reference
            s = null;
	}
}

it is clear that the Student object is going to be collected by the GC. But, what is going to happen with the integers array inside the object. If we analyze the Heap, we can see that the array object is still reachable through the marks reference.

Example of Isolated Reference

Example of Isolated Reference

But what about reaching the marks reference ? Because, it is part of an unreachable object, the reference is considered isolated and, in this case, the referenced object is marked for garbage collecting.

Other topics that are part of this Java tutorial are accessible through Java 6 Tutorial – Contents.

,


  1. No comments yet.
(will not be published)