Tuesday, July 16, 2019

Does 32 bit or 64 bit JVM matter anymore?


There are a few distinct differences and subtle nuances between 32-bit JVM and 64-bit JVM. We thought we will try to clarify them through this question & answer article.

Do I need to understand the difference between 32-bit JVM and 64-bit JVM?

If you aren’t building a performance critical application, you don’t have to understand the difference. The subtle difference between 32-bit JVM and 64-bit JVM wouldn’t make much difference to your application. You can skip reading further.

Does 64-bit JVM perform better than 32-bit JVM?

Most of us think 64-bit is bigger than 32-bit, thus 64-bit JVM performance will be better than 32-bit JVM performance. Unfortunately, it’s not the case. 64-bit JVM can have a small performance degradation than 32-bit JVM. Below is the excerpt from Oracle JDK documentation regarding 64-bit JVM performance:
“Generally, the benefits of being able to address larger amounts of memory come with a small performance loss in 64-bit VMs versus running the same application on a 32-bit VM.
The performance difference comparing an application running on a 64-bit platform versus a 32-bit platform on SPARC is on the order of 10-20% degradation when you move to a 64-bit VM.  On AMD64 and EM64T platforms this difference ranges from 0-15% depending on the amount of pointer accessing your application performs.”

If there is a performance hit, why would anyone use 64-bit JVM?

In 32-bit JVM maximum, addressable memory space is only 2^32 (i.e.~4gb). It means your maximum memory size of your java process can’t be more than 4GB. Due to various additional constraints (such as available swap, kernel address space usage, memory fragmentation, and VM overhead), in practice, the limit is much lower. Below table summarizes maximum heap size (i.e. -Xmx) that you can set on 32-bit JVM:

Whereas if you are running your application on a 64-bit JVM, maximum addressable memory space is 2^64 (i.e. 16 Exabytes). It means your application’s maximum addressable memory size is close to infinite.

Why 64-bit JVM performance can be slower than 32-bit JVM?

This is due to the fact that every native pointer in the system takes up 8 bytes instead of 4.  The loading of this extra data has an impact on memory usage which translates to slightly slower execution depending on how many pointers get loaded during the execution of your Java program.  The good news is that with AMD64 and EM64T platforms running in 64-bit mode, the Java VM gets some additional registers which it can use to generate more efficient native instruction sequences.  These extra registers increase performance to the point where there is often no performance loss at all when comparing 32 to 64-bit execution speed.

What are the things to consider when migrating from 32-bit JVM to 64-bit JVM?

a. GC Pause times

The primary reason to migrate from 32-bit JVM to 64-bit JVM is to attain large heap size (i.e. -Xmx). When you increase heap size, automatically your GC pause times will start to go high, because now there is more garbage in the memory to clear up. You need to do proper GC tuning before doing the migration, otherwise your application can experience several seconds to few minutes pause time. You can use the tools like GCeasy to come up with right GC settings for newly increased heap size.

b. Native Library

If your application is using Java Native Interface (JNI) to access native libraries, then you need to upgrade the native libraries as well. Because 32-bit JVM can use only 32-bit native library. Similarly, 64-bit JVM can use only 64-bit native library.
Whereas if you are running your application on a 64-bit JVM, maximum addressable memory space is 2^64 (i.e. 16 Exabytes). It means your application’s maximum addressable memory size is close to infinite.

Why 64-bit JVM performance can be slower than 32-bit JVM?

This is due to the fact that every native pointer in the system takes up 8 bytes instead of 4.  The loading of this extra data has an impact on memory usage which translates to slightly slower execution depending on how many pointers get loaded during the execution of your Java program.  The good news is that with AMD64 and EM64T platforms running in 64-bit mode, the Java VM gets some additional registers which it can use to generate more efficient native instruction sequences.  These extra registers increase performance to the point where there is often no performance loss at all when comparing 32 to 64-bit execution speed.

What are the things to consider when migrating from 32-bit JVM to 64-bit JVM?

a. GC Pause times

The primary reason to migrate from 32-bit JVM to 64-bit JVM is to attain large heap size (i.e. -Xmx). When you increase heap size, automatically your GC pause times will start to go high, because now there is more garbage in the memory to clear up. You need to do proper GC tuning before doing the migration, otherwise your application can experience several seconds to few minutes pause time. You can use the tools like GCeasy to come up with right GC settings for newly increased heap size.

b. Native Library

If your application is using Java Native Interface (JNI) to access native libraries, then you need to upgrade the native libraries as well. Because 32-bit JVM can use only 32-bit native library. Similarly, 64-bit JVM can use only 64-bit native library.


Java Code Geeks

Monday, July 15, 2019

OutOfMemory related JVM arguments

JVM has provided helpful arguments to deal with OutOfMemoryError. In this article we would like to highlight those JVM arguments. It might come handy for you when you are troubleshooting OutOfMemoryError. Those JVM arguments are:
  1. -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath
  2. -XX:OnOutOfMemoryError
  3. -XX:+ExitOnOutOfMemoryError
  4. -XX:+CrashOnOutOfMemoryError
Let’s discuss these JVM arguments in detail in this article.

1. -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath

Heap dump is basically a snapshot of memory. It contains details about objects that present in memory, actual data that is present within those objects, references originating of those objects. Heap dump is a vital artifact to troubleshoot memory problems.
In order to diagnose OutOfMemoryError or any memory related problem, one would have to capture heap dump right at the moment or few moments before the application starts to experience OutOfMemoryError. It’s hard to do capture heap dump at the right moment manually because we will not know when OutOfMemoryError is going to be thrown. However, capturing heap dumps can be automated by passing following JVM arguments when you launch the application in the command line:
 -XX:+HeapDumpOnOutOfMemoryError and -XX:HeapDumpPath={HEAP-DUMP-FILE-PATH}
Example:
 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/crashes/my-heap-dump.hprof
In ‘-XX:HeapDumpPath’ you need to specify the filepath where heap dump should be stored.
When you pass these two JVM arguments, heap dumps will be automatically captured and written to a specified file path, when OutOfMemoryError is thrown.
Once heap dumps are captured, you can use tools like HeapHeroEclipse MAT to analyze heap dumps.

2. -XX:OnOutOfMemoryError

You can configure JVM to invoke any script when OutOfMemoryError is thrown. Most of the time, OutOfMemoryError doesn’t crash the application. However, it’s better to restart the application, once OutOfMemoryError happens. Because OutOfMemoryError can potentially leave application in an unstable state. Requests served from an unstable application instance can lead to an erroneous result.
Example:
 -XX:OnOutOfMemoryError=/scripts/restart-myapp.sh
When you pass this argument, JVM will invoke “/scripts/restart-myapp.sh” script whenever OutOfMemoryError is thrown. In this script, you can write code to restart your application gracefully.

3. -XX:+CrashOnOutOfMemoryError

When you pass this argument JVM will exit right when it OutOfMemoryError is thrown. Besides exiting, JVM produces text and binary crash files (if core files are enabled). But personally, I wouldn’t prefer configuring this argument, because we should always aim to achieve graceful exit. Abrupt exit can/will jeopardize transactions that are in motion.
I ran an application which generates OutOfMemoryError with this ‘-XX:+CrashOnOutOfMemoryError’ argument. I could see JVM exiting immediately when OutOfMemoryError was thrown. Below was the message in the standard output stream:
 Aborting due to java.lang.OutOfMemoryError: GC overhead limit exceeded
# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (debug.cpp:308), pid=26064, tid=0x0000000000004f4c
#  fatal error: OutOfMemory encountered: GC overhead limit exceeded
#
# JRE version: Java(TM) SE Runtime Environment (8.0_181-b13) (build 1.8.0_181-b13)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.181-b13 mixed mode windows-amd64 compressed oops)
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# C:\workspace\tier1app-svn\trunk\buggyapp\hs_err_pid26064.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
#
From the message, you could see hs_err_pid file to be generated in ‘C:\workspace\tier1app-svn\trunk\buggyapp\hs_err_pid26064.log’. hs_err_pid file contains information about the crash. You can use tools like fastThread to analyze hs_err_pid file. But most of the time information present in hs_err_pid is very basic. It’s not sufficient enough to troubleshoot OutOfMemoryError.

4. -XX:+ExitOnOutOfMemoryError

When you pass this argument, JVM will exit right when OutOfMemoryError is thrown. You may pass this argument if you would like to terminate the application. But personally, I wouldn’t prefer configuring this argument, because we should always aim to achieve a graceful exit. Abrupt exit can/will jeopardize transactions that are in motion.
I ran the same memory leak program with this ‘-XX:+ExitOnOutOfMemoryError’ JVM argument. Unlike ‘-XX:+CrashOnOutOfMemoryError’, this JVM argument did not generate any text/binary file. JVM just exited.

Does 32 bit or 64 bit JVM matter anymore?

There are a few distinct differences and subtle nuances between 32-bit JVM and 64-bit JVM. We thought we will try to clarify them throug...