Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

Java Meta-Coding (Memory Allocation and Management)

0.00/5 (No votes)
16 Apr 2012CPOL6 min read 24.2K  
This article discusses memory management in Java applications, the different data types handling, and the role of garbage collection.

Introduction

The article discusses memory allocation and memory management in Java coding. The article describes what is running beyond Java coding, and what is the actual impact of each coding word. After that, garbage collection details are discussed.

After reading the article, you would be familiar with memory management in Java applications, and will be able to expect what would be the positive and negative impacts of your coding on memory usage.

Data types

The Java programming language has two different data types: primitive and non-primitive (reference) data types. Each type is stored and handled in the memory in a specific way.

Primitive data types

In Java, there are 8 primitive data types (boolean, byte, short, int, long, float, double, char). The variables created according to these data types are stored in the stack. They are handled like the old way of variables in C, C++. A variable is created and stored in the stack once it is declared. It is destroyed and its location is released once the variable scope is finished (block, function…etc.).

Image 1

Figure 1: Primitive variable declaration

After the code in figure 1 is executed, a stack location is created like presented in figure 2.

Image 2

Figure 2: Stack view after primitive variable declaration

After the function myFunction is finished, the location in the stack memory will be removed. This stack allocation is done for primitive variables which are declared as local variables in a function or block. The primitive attributes that are part of an object will be handled like the object itself. The object (non-primitive data types) handling is described in the next section.

Non-primitive (reference) data types

The big part of variables in Java (as a pure object oriented programming language) is the reference objects part. The reference object types are:

  • Built-in wrapper classes (Boolean, Integer, Long…..)
  • Other built-in classes (String, Object……)
  • Any user defined classes

Reference objects are constructed from two parts: the reference object is stored in the stack, and the referenced object (real location) is stored in the heap. The next figure describes the impact of object declaration and initialization.

Image 3

Figure 3: Non-primitive object declaration

After the snippet code in figure 3 runs, the stack memory is affected as described in figure 4.

Image 4

Figure 4: Stack view after non-primitive object declaration

If you try to use this object now, you will get a null pointer exception because the reference “X” points to no memory location till now.

Image 5

Figure 5: Non-primitive object declaration and initialization

The snippet code in figure 5 allocates the memory location in the heap of this student object.

Image 6

Figure 6: Memory view after non-primitive object initialization

Now the real object location is stored in heap memory, a reference holding this location address is stored in the stack. It is something like pointers in C and C++, but with some differences like, in Java, you don’t have the control to move the pointer to a different memory location like in C, the management of these pointers is the responsibility of the JVM.

This rule is applied for all non-primitive objects in Java. The array is also considered as a non-primitive object. A reference to the array is stored in the stack, while the actual array nodes are allocated in the heap. This rule explains why the developer should call “new” during array initialization even if it is an array of primitive data types like presented in figure 7.

Image 7

Figure 7: Array object declaration and initialization

The String class is a special case of classes in Java. You could define a string object by one of the ways presented in figure 8.

Image 8

Figure 8: String object declaration and initialization

For simplicity, Java enables you to define a String object without calling “new” like in the “y1” object in figure 8. But both variables defined in figure 8 have a reference object in the stack, and a heap location containing the actual string value.

While the String class is immutable, any change in the object value would raise a new location reservation in the heap and the old location would be kept with no reference. Figures 9 and 10 present sample code and its reflection on the memory locations.

Image 9

Figure 9: String declaration and initialization example

Image 10

Figure 10: Memory view of the string example

The object “John” is not needed now because no reference points to it. This point opens the “Garbage Collection” topic.

Garbage collection

Garbage collection is the functionality that Java provides to manage memory and handle all non-primitive objects in the heap memory. The garbage collector is a low priority thread that runs from time to time to check if there are any used memory locations and there are no references to these locations. The garbage collector returns these used locations to be heap free locations, and could be reused if needed. In the string example in figures 9 and 10, the memory location “John” is eligible for garbage collection because there is no object referring to it, while “Ali” and “Adams” are not eligible for that, because they are used by objects “x1” and “y1”.

The “finalize ()” function is called automatically on the object before garbage collection releases this object to memory. Java provides this capability to give the developer the chance to do some destructor work (release resources….etc.).

The garbage collection execution runs in parallel with the main application execution, so the developer can not force the garbage collector to work, he could only recommend garbage execution by “System.gc()”. Although the developer has many ways to manage his memory, one of the ways is: setting a start and maximum heap size as described in figure 11.

Image 11

Figure 11: Heap memory parameters example

If you take a look at the heap memory details, we will find that the JVM divides the heap memory into three main sections as presented in figure 12.

Image 12

Figure 12: Heap memory details

As presented in figure 12, the heap memory is constructed from “Young Generation”, “Old Generation”, and “Permanent Area”. The permanent area is not used for application objects, so it is out of garbage collection work. The new objects are inserted in the young generation area in the first stage (Eden space). Every now and then, garbage collection performs a minor collecting activity, if the object still has a reference after a subsequent of this minor collecting, the object would be moved to supervisor 1 and then supervisor 2 if it is still used.

Meanwhile a Major collecting process is performed from time to time (it takes some time of the main application performance time, because it is more complex than the minor collecting activity). If the object is still needed, it would be moved to the “old generation” area. The ratio between these young and old areas could be managed through JVM parameters as described in figure 13, which means the ratio young:old is 1:2.

Image 13

Figure 13: Heap memory partitions setting parameters

References

History

  • Version 1: 15 April 2012, Initial version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)