1

I am testing my java application and I noticed that a Java 64 bit version uses much more than executing the application in a Java 32 bit version.

The servers I tested was a Windows 7-64 bit and a Solaris-64 bit, but the same behavior has happened in both cases. By the way, the application runs with default VM parameters and Java version used was 8u65s.

As my servers are 64 bit that right choice would take a Java 64 bit, but is there any reason for this? In what case 32 bit version is better than a 64 bit?

Memory allocated in both:

32-bit : 74mb
64-bit: 249mb
Carlos Alberto
  • 7,761
  • 13
  • 52
  • 72
  • Can you provide more information about what JVM you're using, what code you're running, what JVM flags you provided, and whether this memory usage is immediate versus over time? With just the information provided I'm not sure we can give a good answer to your question. – templatetypedef Feb 16 '16 at 19:19
  • 2
    Sidenote: The architecture name is 32/64 **bit**, not **bits** – OneCricketeer Feb 16 '16 at 19:21
  • The Java version is 8u65, no VM parameters were set in both cases. I am executing a Spring application but other ones suffered the same behavior. I saw the memory use via system manager on Windows. – Carlos Alberto Feb 16 '16 at 19:23
  • 2
    See this answer from a previous post: http://stackoverflow.com/a/4408987/3299157 – Ageonix Feb 16 '16 at 19:23
  • Don't look at your JVM from the outside, use tools that show memory consumption from the inside (VisualVM, ...) – Marged Feb 16 '16 at 19:27
  • simple google search for "java 64bit uses more memory" returns plenty of valid hits. – jtahlborn Feb 16 '16 at 19:34
  • In any case (even non-Java issues) use 32bit with RAM up to 4GB and 64bit for all above. Any new server today won't have less than 8GB. – PeterMmm Feb 16 '16 at 19:41
  • I read that Solaris only has 64bits version, and for SPARC server is still slower ("SPARC is on the order of 10-20% degradation when you move to a 64-bit VM") – Carlos Alberto Feb 16 '16 at 19:51
  • The change from 74 mb to 249 mb can be fully explained by changed command line defaults between Java 7 and Java 8. See [my answer below](http://stackoverflow.com/a/35521830/1504556). – peterh Feb 20 '16 at 10:20

2 Answers2

2

This is normal behavior for Java (as well as Microsoft .NET), mostly because of their pointer model, and also their garbage collection model.

An object variable is actually a pointer to an object on the heap. In 64-bit versions, this pointer requires twice as much space. So, the pointers stored in containers will require more memory, and so will the pointers that are held by the garbage collector to allow collection. Since objects are mostly made up of pointers to other objects, the difference between 32-bit and 64-bit adds up very fast.

Added to that, the garbage collector has to keep track of all of these objects efficiently, and in 64-bit versions, the collector tends to use a larger minimum allocation size so it doesn't have to keep track of as many slices of memory. This makes sense because objects are bigger anyway. I believe the minimum sizes are typically 16 bytes in 32-bit mode and 32 bytes in 64-bit mode, but those are entirely up to the specific virtual machine you are using, so they will vary.

For example, if you have an object that only requires 12 bytes of heap memory, and you are running on a virtual machine with a 32-byte minimum allocation size, it will use 32 bytes, with 20 of those bytes wasted. If you allocate the same object on a machine with a 16-byte minimum size, it will use 16 bytes, with 4 wasted. The alternative to this is to waste a lot more memory in keeping track of those blocks, so this is actually the best approach, and will keep your application's performance and resource utilization balanced.

Another thing to keep in mind is that the Java runtime allocates blocks of memory from the operating system for its heap, then the program can allocate memory out of those blocks. The runtime tries to stay ahead of your program's memory needs, so it will allocate more than is needed and let your program grow into it. With a higher minimum allocation size, the 64-bit runtime will allocate bigger blocks for its heap, so you will have more unused memory than with a 32-bit runtime.

If memory consumption is a serious constraint for your particular application, you might consider native-compiled C++ (using actual C++ standards, not legacy C with pointers to objects!). Native C++ typically requires 1/5 of the memory of Java to accomplish the same thing, which is the reason that native code tends to be more popular on mobile devices (C++ and Objective C). Of course, C++ has its own issues, so unless you have a desperate need to reduce memory consumption, it is probably best to accept this as normal behavior and keep using 64-bit Java.

Matt Jordan
  • 2,133
  • 9
  • 10
  • Also, 64- vs. 32-bit is one of the factors the runtime considers when deciding whether to run in server or client mode, and server mode starts with a higher initial memory allocation. – erickson Feb 16 '16 at 20:18
  • Yes 64 bit Java requires more memory mostly because of larger pointers. But that doesn't explain a 3x increase. I would recommend to do heap dumps to compare where memory is used – kohlerm Feb 17 '16 at 06:50
  • @kohlerm. The 3x change can be explained by changed default values for `-Xms`. See my answer [here](http://stackoverflow.com/a/35521830/1504556). – peterh Feb 20 '16 at 11:13
2

It is correct that a 64-bit memory model takes up more memory.

Besides that I just wanted to mention a Solaris gotcha, so this is not really a full answer to your question, but the answer below can fully explain the difference from 74mb to 249mb that you are seeing.

It is correct that there's no longer a 32-bit version Java for Solaris, as is also the case for Mac OS X. Beware that for Java 7 on Solaris you would always get the 32-bit Java (even if you had installed 64-bit Java) unless you explicitly requested the 64-bit with the -d64 flag. So be sure not to compare apples and oranges here. A lot of people on Solaris thought that they have been running the 64-bit Java because they had installed it, unaware that it had to explicitly requested.

For Java 8 on Solaris there's no point in specifying -dXX as there's only a 64-bit version.

Therefore - simply as a consequence of this - the default values for memory settings have changed. What I'm saying is that solely as a consequence of this (and not the discussion about memory pointers) it will seem as if your Java 8 on Solaris is taking up more memory from the OS. This is in fact a mirage.

Here's a recap from a 16 GB system (the values will change depending on your amount of installed RAM):

Java 7 on Solaris

With Java 7 on Solaris without further command line options you would get a 32-bit memory model (-d32 is implied even with 64-bit version installed) and default values as follows:

memory model:  32 bit
-Xms default :  64 MB
-Xmx default :   1 GB

If you explicitly used -d64 you would get:

memory model:  64 bit
-Xms default :  256 MB
-Xmx default :   4 GB

Java 8 on Solaris

With Java 8 on Solaris without further command line options you would get a 64-bit memory model (-d64 is implied, -d32 is now illegal) and default values as follows:

memory model:  64 bit
-Xms default :  256 MB
-Xmx default :   4 GB

As for your comment that you've read that: "SPARC is on the order of 10-20% degradation when you move to a 64-bit VM". I doubt it. I can see that you've read it here but that document applies to Java 1.4 and potentially Java 5. A lot has happened since then.

peterh
  • 18,404
  • 12
  • 87
  • 115