One of the best thing in java is that the developers are not required to handle the memory allocations when the objects are created. The JVM does that for us. Most of the time we just need the outer layer knowledge of heap memory and garbage collector. I will share some really interesting investigations that I had. I is a huge topic and I am writing from a point of view of a web application developer, what all minimum I thought we should understand about it.
There are number of good tools available to profile the java applications some of them are,
Out of these Your Kit and JProfilers needs licences and others are free to use products. We are going to use VisualVM. It is a simple yet powerful tool and comes bundled inside the JDK. It has power list of plugins that you can download and use. To start using VisualVM, go to your <JDK_HOME>\bin and run the jvisualvm.exe. I found the below articles it useful to get going.
Since we are talking about memory here make sure you install the Visual GC plugin on the VisualVM as told in this article.
Setting the stage – JVM Memory Structure
The JVM Memory is divided in to 3 parts as shown in the below image. In our applications we are concerned about the Heap Memory. We can input this value to JVM using the parameters,
-Xmx<size> – to set the maximum Java heap size
-Xms<size> – to set the initial Java heap size
The non-Heap memory stores per-class structures such as runtime constant pool, field and method data, and the code for methods and constructors, as well as interned Strings.
The one common confusion is about the stack memory and heap memory. This is well explained here.Stack values only exist within the scope of the function they are created in. Once it returns, they are discarded. Java only stores primitives on the stack. This keeps the stack small and helps keeping individual stack frames small, thus allowing more nested calls. Objects are created on the heap, and only references (which in turn are primitives) are passed around on the stack.
Now, Lets get real. Given below the image from Visual GC, a plugin inside the VisualVM as told earlier. We see many graphs here a detailed decription of the output is available here.
The Game begins – What happens when the application runs
When the objects are created, they reside inside the Eden. When the Garbage collector(GC) runs, if the object is dead (means they are no active references) it is flushed out otherwise they are moved to S1(Survivor Space 1) or S2. This is called a GC cycle. Internal GM algorithm decides the frequency of the GC cycle. Eden + S1 + S2 section of Heap memory is called as Young generation. Objects that survives a fixed number of GC cycles are moved in to Old Gen space. Most number of java objects die as infant and never reach Old Gen. This typically includes local variables which are flushed after the methods are executed.
The frequency of GC cycles inside the Old Gen is much lesser than Young Gen. Typical examples of Old Gen objects are singletons, cached objects and other application wide used data.
When things do not go as per the plan
In a typical application there will be less variation inside the Old Gen space. If the Old Gen space grows linearly with time even after the GC cycle that would lead to a OutOfMemoryError. This might be a indication of a memory leak inside the code. However we might need to use a profiler to find out the exact reason for the same. Here is a Dzon article on some of the Causes of Java EE Enterprise Performance Problems.
These are the basic building blocks of how JVM memory is organized and reacts when the application is executed. From this point there are lots of topics including tuning the memory parameters and garbage collector. I will add some of the useful resources related to this.
1. Java Performance Tuning, Profiling, and Memory Management
2. InfoQ Presentation : Diagnosing Web Application OutOfMemoryErrors
3. InfoQ Presentation : Everything I Ever Learned about JVM Performance Tuning @twitter
4. InfoQ Presentation : Extreme Performance Java
5. Java theory and practice: Garbage collection and performance
Bulletproof Java Code: A Practical Strategy for Developing Functional, Reliable, and Secure Java Code
Use Java? If you do, you know that Java software can be used to drive application logic of Web services or Web applications. Perhaps you use it for desktop applications? Or, embedded devices? Whatever your use of Java code, functional errors are the enemy!
To combat this enemy, your team might already perform functional testing. Even so, you're taking significant risks if you have not yet implemented a comprehensive team-wide quality management strategy. Such a strategy alleviates reliability, security, and performance problems to ensure that your code is free of functionality errors.Read this article to learn about this simple four-step strategy that is proven to make Java code more reliable, more secure, and easier to maintain.