Understanding Weblogic Memory Allocation, Heap Size & Garbage Collection
Those who’ve worked with PeopleSoft application for long will remember days when PeopleSoft application performance issues were a common occurrence. Hardware and software technology strides in the recent years have made PeopleSoft performance issues a thing of the past. Now-a-days, it is common to have an acceptable performance of PeopleSoft application right out of the box without having to pay a thought on performance. However, it always pays to keep your PeopleSoft application optimally tuned, so you can derive the best performance while paying the least.
In this article, we’ll discuss Java memory management and how it affects performance. Learning Java memory management is a skill that will serve you well outside of PeopleSoft application as well.
Brief Background of Java
The first version of Java appeared in 1995 with a slogan, WORA or “Write Once, Run Anywhere.” Since then it has become one of the most popular and widely used computer language. What makes Java run everywhere is the fact that it is not just a language, but also a platform!
The programs written in Cobol, Java, C or any other programming language have to be compiled i.e. translated to machine codes to let computers understand them. Most compilations are hardware specific i.e. machine code for a particular hardware may not work for another hardware. That is not the case with Java! Instead of translating the program into machine codes, the Java compiler converts it to an intermediate language called bytecode. And this bytecode is executed not on the hardware itself, but on a JVM (Java Virtual Machine).
What is JVM?
JVM stands for Java Virtual Machine.
JVM is a hardware specific special software that serves as a translator from bytecode to the language of machine codes. The JVM loads the code, verifies the code, executes the code, performs memory management and provides the runtime environment.
Memory management is all about allocation of objects — finding free spots for the new objects and removing old objects to create more free space for new objects.
Java objects reside in an area called the heap.
The Heap is created when the JVM starts up and may increase or decrease in size while the application runs. When the heap become full, objects that are no longer used are cleared, thus making space for new objects. This process of removing old objects is known as garbage collection.
Note — JVM uses more memory than just the heap. For example Java methods, thread stacks and native handles are allocated in memory separate from the heap, as well as JVM internal data structures.
The Heap is created when the JVM starts up and may increase or decrease in size while the application runs. The heap is divided into two areas known as generations. These two areas are called the nursery (or young space) and the old space.
Garbage collection is the process by which old objects are moved in order to make space of new objects.
The nursery is a part of the heap reserved for allocation of new objects. When the nursery becomes full, garbage is collected by running a special young collection, where all objects that have lived long enough in the nursery are promoted (moved) to the old space, thus freeing up the nursery for more object allocation. When the old space becomes full garbage is collected there, a process called an old collection.
Most objects in a nursery are temporary and short lived. A young collection is designed to be swift at finding newly allocated objects that are still alive and moving them away from the nursery. Typically, a young collection frees a given amount of memory much faster than an old collection or a garbage collection of a single-generational heap (a heap without a nursery).
To distinguish between recently allocated objects and objects that have been around for a while in the nursery, the JVM uses a keep area. The keep area contains the most recently allocated objects in the nursery and is not garbage collected until the next young collection.
The more objects a Java application allocates, the more resources will be used for memory management. A correctly tuned memory management system minimizes the overhead inflicted by garbage collection and makes object allocation fast.
Setting the Heap Size
The heap size has an impact on allocation speed, garbage collection frequency and the garbage collection times.
A small heap will become full quickly, which will require frequent garbage collection. It is also prone to more fragmentation, making object allocation slower.
A large heap introduces a slight overhead in garbage collection times because garbage collection takes longer. A heap that is larger than the available physical memory in the system must be paged out to disk, which leads to long access times or even application freezes, especially during garbage collection. In general, the extra overhead caused by a larger heap is smaller than the gains in garbage collection frequency and allocation speed, as long as the heap doesn’t get paged to disk.
A nursery that is so small that few or no objects have died before a young collection is started is of very little use, and neither is a nursery that is so large that no young collections are performed between garbage collections of the whole heap that are triggered due to allocation of large objects in old space. An optimal nursery size for maximum application throughput is such that as many objects as possible are garbage collected by young collection rather than old collection. This value approximates to about half of the free heap.
Thus a good heap size setting would be a heap that is as large as possible within the available physical memory
Syntax for setting the heap size is: -Xms:<min size> -Xmx:<max size>
-Xms:<min size> sets the initial and minimum heap size.
-Xmx:<max size> sets the maximum heap size.
It is usually recommended that you set -Xms and -Xmx to the same value. It gives you a good controlled heap size to begin with irrespective of the environment type.
JVM heap size is specified in setEnv using the JAVA_OPTIONS_xxx where xxx denotes the Operating System variable. You only need to set the variables that correspond to the operating system where the WebLogic server is running.
The Microsoft Windows setEnv.cmd script contains the following default setting:
SET JAVA_OPTIONS_WIN=-jrockit -XnoOpt -Xms512m -Xmx512m -Dtoplink.xml.platform=oracle.toplink.platform.xml.jaxp.JAXPPlatform
The UNIX standard setEnv.sh script contains the following default settings for supported Linux and UNIX platforms:
JAVA_OPTIONS_AIX="-Xms128m -Xmx256m -Dtoplink.xml.platform =oracle.toplink.platform.xml.jaxp.JAXPPlatform -Dcom.sun.xml.namespace.QName.useCompatibleSerialVersionUID=1.0" JAVA_OPTIONS_HPUX="-Xms256m -Xmx256m -XX:MaxPermSize=256m -Dtoplink.xml.platform=oracle.toplink.platform.xml.jaxp.JAXPPlatform -Dcom.sun.xml.namespace.QName.useCompatibleSerialVersionUID=1.0" JAVA_OPTIONS_LINUX="-jrockit -XnoOpt -Xms512m -Xmx512m -Dtoplink.xml.platform=oracle.toplink.platform.xml.jaxp.JAXPPlatform -Dcom.sun.xml.namespace.QName.useCompatibleSerialVersionUID=1.0" JAVA_OPTIONS_SOLARIS="-Xms256m -Xmx256m -XX:MaxPermSize=256m -Dtoplink.xml.platform=oracle.toplink.platform.xml.jaxp.JAXPPlatform -Dcom.sun.xml.namespace.QName.useCompatibleSerialVersionUID=1.0"
In a multi-server domain, the platform-specific versions of the JAVA_OPTIONS environment variable that appear in the setEnv script apply only to managed servers. The administration server doesn’t use any of these variables, but it assumes default JVM heap size values of “-Xms256m -Xmx256m”.
To adjust the JVM heap size for the administration server, add the environment variable JAVA_OPTIONS_ADMINSERVER following the last entry for JAVA_OPTIONS for your platform, and set it to your required minimum and maximum values, for example:JAVA_OPTIONS_ADMINSERVER=”-Xms128m -Xmx256″
Heap Size in Elasticsearch
Oracle recommends 64 GB RAM and a minimum of 32 GB available RAM is required to run an Elasticsearch environment.
An environment variable called ES_HEAP_SIZE can be used to adjust the heap size. While 64 GB may be too much, 32 GB is good enough in most of the cases. The standard recommendation is to give 50% of the available memory to the Elasticsearch heap, while leaving the other 50% free. The memory is used by Lucene for caching in-memory data structures.
As a standard practice never set the heap size greater than 30 GB, as setting a higher value would not use JAVA compressed pointers, wastes memory, reduces CPU performance, and makes the garbage collection (GC) struggle with large heaps.
If your application suffers from out of memory errors, it is about time that you start playing with the min and max values of JVM heap size.