As I had to study their operation, I decided to post about the basic concepts of memory in Java.
To begin wtih, Java divides memory into two distinct segments:
- Heap: User objects, variables, …
- Non-Heap/Perm: code, metadata, …
The one that interests us is the Heap, as it is what we can “control”. You can configure the Non-Heap Memory (Perm) size with the parameter
MaxPermSize. But this is only useful if the application is loaded or dynamically generate many different classes.
The heap is divided into two generations according to their lifetime:
- Young Generation
- Old Generation
Usually the younger generation is composed of local variables and temporary objects, while the older generation usually consists of structures that are necessary during the execution: configurations, viewports, …
Also, the younger generation is divided into two:
- Eden: This is where objects are created initially
- Survivor: It’s like the limbo through which we pass from the young to the old generation. It is usually composed into two parts.
You can specify the ratio between the space of the young generation and old generation with the virtual machine parameter
-XX: NewRatio .
The Garbage Collector (
Garbage Collector ) performs two types of periodic tasks:
- Minor Collection: Reviews quickly the younger generation.
- Major Collection: Reviews all the memory, mainly the older generation.
The garbage collector runs at the same time as the normal program execution and each execution involves a small pause (usually milliseconds) in all the threads that are running at that time. As memory remains more or less freed, the Garbage Collector will be limited to minor collections, to not interfere with the flow of the application.
To get a better idea of how it works, you can add
-verbose:gc to the virtual machine. This command will print each time you run the garbage collector and the area of memory that has been successfully unleashed.
There are several implementations of the garbage collector, being the most common the
Serial Collector. This implementation, as well as being the simplest, uses only one processor. If you’re using a more powerful machine with multiple processors and a good amount of physical memory, you can activate the
Parallel Collector , which uses multiple CPUs at the same time. This improves the way in which the garbage collector works, but it can also paralyze the flow of normal execution of the application.
For proper operation and cleaning of memory, we should have little short-lived temporary objects better than long, durable objects. The small temporary objects will stay in the Eden, so they will be collected much earlier and much faster.
Also, having unused objects in memory, although they do not disrupt the execution of the program, will slow the execution of the garbage collection, because you have to process them over and over again to check if they can be deleted.
At some point it may seem tempting to force a Garbage Collector implementation calling
System.gc() . However, this will force a major collection asynchronously, breaking up all the heuristics of the Garbage Collector. It is so discouraged that there is an option in the virtual machine to disable these calls:
-XX: + DisableExplicitGC .
To help the task of garbage collection, there are three types of references :
- Weak : It does not prevent the garbage collector take it.
- Soft : As the weak, but the garbage collector a little more respect him and takes him only if you need memory. Useful for caching, but can be misleading.
- Phantom: Always returns null, not really accesses the object, but can serve serve to clear before they take the object that binds it.
A class that explains quite well the operation of such references is
WeakHashMap : it works as a HashMap, but using Weak References. Thus, if the key contains an object which is only referenced in the HashMap, it is no longer considered useful and is cleared.
- Summary of memory in Java
- JConsole: the basic program of monitoring of Java
- About Garbage Collector (Garbage Collector)