Ben J. Christensen

32-bit versus 64-bit JDK Memory Usage

Summary of analysis performed September 2006.

Testing Strategy

To ensure the tests performed were reliable and behaved the same every time with as few variables as possible, a simple program (a single java class) was written which loops indefinitely, adding objects to a collection until it runs out of memory.

This test was performed with both Integer and String objects, and then executed with 3 different JVMs with varying heap settings.

The results and details of these tests are documented in later chapters.

JVMs tested:
– JDK 1.4.2 32-bit
– JDK 1.5 32-bit
– JDK 1.5 64-bit

Operating Systems Tested
– Solaris 10 on Opterons
– Suse Linux 10 on Opterons

The tests are far from exhaustive, but were enough to derive numbers and patterns whereby the JVMs can be sized accurately and recommendations made.

Findings

- Tests performed consistently on both Linux and Solaris (except for maximum heap sizes)
– JDK 5 64-bit takes between 40% – 50% more memory on average than either 32-bit JVM
– JDK 1.4 32-bit is slightly more memory efficient than JDK 5 32-bit
o It is slightly better than JDK 5 32-bit in Integer tests
o It is exactly the same as JDK 5 32-bit in String tests

- Solaris 10 can run a 32-bit JVM up to 3.5GB
– Suse Linux can run a 32-bit JVM up to 2GB
– A 64-bit JVM was successfully run at 20GB on Suse Linux
– A 2GB 32-bit JVM is approximately equivalent to a 3GB 64-bit JVM in number of objects stored
o ie. On Suse Linux, if more than 2GB heap is needed, then one must jump to a 3GB 64-bit JVM to achieve the same amount of storage
o ie. On Solaris, if more than 3.5GB heap is needed, then one must jump to a 5GB 64-bit JVM to achieve the same amount of storage

Recommendations

Based upon these findings, it is recommended that JDK 5 32-bit be used as the default JVM, and 64-bit used if more memory is needed than what can be allocated to a 32-bit JVM with the understanding of the ratio one must increase to account for the change to a 64-bit data model.

The reasons for choosing JDK 5 over JDK 1.4 are:

- JDK 5 is the current recommended production JVM from Sun Microsystems
o It has been out for more than 2 years and is at its 8th maintenance release (JDK 1.5_08)

- General performance improvements from JDK 1.4 to JDK 5
o http://java.sun.com/j2se/1.5.0/docs/guide/performance/speed.html
o http://java.sun.com/j2se/1.5.0/docs/guide/vm/index.html

- Improved garbage collection algorithms, particularly for multi-processor machines
o http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html

- 64-bit JVM available on AMD Opterons when larger heap sizes required (not available for JDK 1.4)
o http://java.sun.com/j2se/1.5.0/docs/relnotes/features.html#platform_proc64

Summary

The tests performed confirmed that the 64-bit JVM does indeed use more memory than the 32-bit JVMs, but that it behaves consistently and can be calculated, and therefore planned for.
It is recommended to use JDK 5 32-bit as the default JVM, and the 64-bit variant when larger heap sizes are required.

Java Source File: MemoryTest.java

About these ads

Filed under: Code, Performance

10 Responses

  1. Christian Bourque says:

    Hi Ben!

    Very interesting article!

    Could you add a link to the Java class you have used for your benchmarks?

    I would like to test it on my new server with openSUSE 10.2 (64-bit)…

    Thanks

    Christian

  2. Ben Christensen says:

    Hi Christan,

    I’ve added a link to the bottom of the article with the source file. You’ll need to rename it from a .doc ending to .java again … WordPress won’t allow attaching a .java file.

    It’s nothing fancy, but did the job in helping me to validate the memory discrepancies we were seeing in our environments.

    Hope it helps in some way.

    Ben

  3. kumar says:

    very useful post. Indeed nice analysis.

  4. guliaiete says:

    Hi Ben
    I have a pure java + Apple Web Object 5.5 web application, right now application is on 32bit processor with 32bit JVM having 16gb ram but still client get “java.lang.OutOfMemoryError: Java heap space” so we are planning to move it on 64bit jvm and 64 bit processor and 32 gb ram. Here my question is will i need to recompile my application before it live on production server or there is no need of recompilation? ..one more thing i want to mention it’s a pure java application no native code. Thanks in advance waiting for your response.

    • Ben Christensen says:

      Hi guliaiete,

      No you don’t need to recompile the java application. Java bytecode can be run in either 32-bit or 64-bit JVMs.

      However, running the code on your new machine won’t automatically solve your problem – it’s the JVM arguments that define how much memory the application can use.

      Just because the machine has 16GB or 32GB of ram does not mean the java application will have access to it. You must tell the JVM how much memory to allow it to access.

      Official documentation can be found here: http://download.oracle.com/javase/6/docs/technotes/tools/windows/java.html

      -Xmxn
      Specify the maximum size, in bytes, of the memory allocation pool. This value must a multiple of 1024 greater than 2MB. Append the letter k or K to indicate kilobytes, or m or M to indicate megabytes. The default value is chosen at runtime based on system configuration. For more information, see HotSpot Ergonomics
      Examples:
      -Xmx83886080
      -Xmx81920k
      -Xmx80m

      For example, the following will run the app and give it a maximum of 2gb that it can use:

      java -Xmx2g com.myapp.MyMain

      That can work on most 32-bit JVMs.

      Or, to give 4gb you would do:

      java -Xmx4g com.myapp.MyMain

      To force an app to 32-bit or 64-bit it can typically be accomplished via arguments such as this:

      java -d32 com.myapp.MyMain
      java -d64 com.myapp.MyMain

      The -server option does the same thing as -d64 on most (if not all) modern JVM installations.

      Hope this information helps. Good luck with your app.

      Ben

  5. […] Netbeans mit 32bit Java auf 64bit Fedora Linux (GNOME) Publiziert am 27. Februar 2011 von vinz TweetIch verdiene meine Brötchen ja damit, dass ich Java-Code eintippe. Damit das möglichst schnell geht brauche ich viel viel Speicher und eine schnelle CPU. Aktuelle Rechner sind prädestiniert für 64bit Betriebssysteme und Anwendungen. Allerdings hat die Java-Laufzeitumgebung ein Problem, nämlich dass die 64bit-Variante ziemlich deutlich mehr Speicher verbraucht als die 32bit-Version. Die Ursache liegt in den doppelt so großen Pointern (8 Byte statt 4 Byte) die für jedes Objekt (und das sind viele) erzeugt werden. In meiner Erfahrung fressen Netbeans zusammen mit Tomcat, Spring, Hibernate, etc. bei einer 64-bittigen VM schnell mal 2 GB wo die 32-Bit-Variante nur 1GB braucht. Zu dem Thema gibt es auch einen recht informativen Post. […]

  6. Dave says:

    Interesting article. I just read http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#64bit_description and I have a minor nitpic with your conclusion that it is possible to calculate and plan for how much more memory you’ll need for a 64 bit deployment – it is not primitives that are larger but pointers, so the amount of extra memory needed will fluctuate according to the number of allocations your software makes.

    • Ben Christensen says:

      Dave,

      You are definitely correct in referencing the Oracle FAQ that primitives do NOT increase, but the pointers (object references) do.

      4+ years ago when I wrote this there were several situations I was in where misunderstanding existed as to why apps were running out of memory when switching from 32-bit to 64-bit, or why a 64-bit app required more memory than running in 32-bit mode.

      Hence the writeup to basically provide a practical example of how to “calculate” the average increase in memory an application would need from going to 64-bit and more importantly to prove that it was something to be expected and not a “fault” of a given application. It is by no means concrete and it fully depends on what you’re doing in the app.

      If an app has a single object that contains an primitive byte[10000000] array then obviously the “average” of my calculations will not apply, but that’s also not how most objects/primitives exist in typical apps.

      Every app would need to do their own testing and every developer needs to understand the difference between primitives and objects in Java.

      Hope this helps provide some context.

      Ben

  7. good stuff – very interesting and useful

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Twitter Updates

View Ben Christensen's profile on LinkedIn
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: