Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weird behavior of Java -Xmx on large amounts of ram

Tags:

java

windows

You can control the maximum heap size in java using the -Xmx option.

We are experiencing some weird behavior on Windows with this switch. We run some very beefy servers (think 196gb ram). Windows version is Windows Server 2008R2

Java version is 1.6.0_18, 64-Bit (obviously).

Anyway, we were having some weird bugs where processes were quitting with out of memory exceptions even though the process was using much less memory than specified by the -Xmx setting.

So we wrote simple program that would allocate a 1GB byte array each time one pressed the enter key, and initialize the byte array to random values (to prevent any memory compression etc).

Basically, whats happening is that if we run the program with -Xmx35000m (roughly 35 gb) we get an out of memory exception when we hit 25 GB of process space (using windows task manager to measure). We hit this after allocating 24 GB worth of 1 GB blocks, BTW, so that checks out.

Simply specifying a larger value for -Xmx option makes the program work fine to larger amounts of ram.

So, what is going on? Is -Xmx just "off". BTW: We need to specify -Xmx55000m to get a 35 GB process space...

Any ideas on what is going on?

Is their a bug in the Windows JVM?

Is it safe to simply set the -Xmx option bigger, even though there is a disconnect between the -Xmx option and what is going on process wise?

like image 695
SvrGuy Avatar asked Mar 07 '11 23:03

SvrGuy


2 Answers

Theory #1

When you request a 35Gb heap using -Xmx35000m, what you are actually saying is that to allow the total space used for the heap to be 35Gb. But the total space consists of the Tenured Object space (for objects that survive multiple GC cycles), the Eden space for newly created objects, and other spaces into which objects will be copied during garbage collection.

The issue is that some of the spaces are not and cannot be used for allocating new objects. So in effect, you "lose" a significant percent of your 35Gb to overheads.

There are various -XX options that can be used to tweak the sizes of the respective spaces, etc. You might try fiddling with them to see if they make a difference. Refer to this document for more information. (The commonly used GC tuning options are listed in section 8. The -XX:NewSpace option looks promising ...)


Theory #2

This might be happening because you are allocating huge objects. IIRC, objects above a certain size can be allocated directly into the Tenured Object space. In your (highly artificial) benchmark, this might result in the JVM not putting stuff into the Eden space, and therefore being able to use less of the total heap space than is normal.

As an experiment, try changing your benchmark to allocate lots of small objects, and see if it manages to use more of the available space before OOME-ing.


Here are some other theories that I would discount:

  • "You are running into OS-imposed limits." I would discount this, since you said that you can get significantly greater memory utilization by increasing the -Xmx... setting.

  • "The Windows task manager is reporting bogus numbers." I would discount this because the numbers reported roughly match the 25Gb that you think your application had managed to allocate.

  • "You are losing space to other things; e.g. the permgen heap." AFAIK, the permgen heap size is controlled and accounted independently of the "normal" heaps. Other non-heap memory usage is either a constant (for the app) or dependent on the app doing specific things.

  • "You are suffering from heap fragmentation." All of the JVM garbage collectors are "copying collectors", and this family of collectors has the property that heap nodes are automatically compacted.

  • "JVM bug on Windows." Highly unlikely. There must be tens of thousands of 64bit Java on Windows installations that maximize the heap size. Someone else would have noticed ...


Finally, if you are NOT doing this because your application requires you to allocate memory in huge chunks, and hang onto it "for ever" ... there's a good chance that you are chasing shadows. A "normal" large-memory application doesn't do this kind of thing, and the JVM is tuned for normal applications ... not anomalous ones.

And if your application really does behave this way, the pragmatic solution is to just set the -Xmx... option larger, and only worry if you start running into OS-level issues.

like image 160
Stephen C Avatar answered Sep 20 '22 03:09

Stephen C


To get a feeling for what exactly you are measuring you should use some different tools:

  1. the Windows Task Manager (I only know Windows XP, but I heard rumours that the Task Manager has improved since then.)
  2. procexp and vmmap from Sysinternals
  3. jconsole from the JVM (you are using the SunOracle HotSpot JVM, aren't you?)

Now you should answer the following questions:

  • What does jconsole say about the used heap size? How does that differ from procexp?
  • Does the value from procexp change if you fill the byte arrays with non-zero numbers instead of keeping them at 0?
like image 40
Roland Illig Avatar answered Sep 20 '22 03:09

Roland Illig