does large value for -Xmx postpone Garbage Collection? - java

I have a lot of JVMs running on a Linux Redhat with 32GB of physical memory and a 32GB of virtual memory. these JVMs are configured to have a total value for Xmx which is more than 32GB and might have the Linux used its virtual memory.
my question is that if I specify the Xmx more than required heap size would it delay the Garbage Collection and as a result allocate more heapsize than necessary? so that it will cause the OS to allocate memory from its virtual memory which leads to a dwindled performance.

The JVM reserves the maximum heap size (as well as other memory areas) on startup. This means if you have a maximum heap size of 32 GB it will use about 33-35 GB of virtual memory including shared libraries threads etc.
Its is worth nothing that if you make the maximum heap size 32 GB it has to use 64-bit references and you can end up with less usable memory than a JVM with a maximum heap of 24 GB and it will use 32-bit references. Some people have estimated that if you make the heap size 32 Gb or more you have to increase it to 48 GB to get more usable memory.
Given the size of your machine I suggest you limit the heap to 24 GB (or less) and where possible use off heap memory as this can have both performance advantages and greater scalability.
If you have a low GC program and you want to avoid collection you can create a massive eden size and GC once per day or once per week. To do this you have to keep your garbage discarded to a minimum and you could create an eden size of say 20 GB in which case provided you create less than 20 Gb in a day you can avoid triggering any GCs (even minor ones) and run a full GC as an over night maintainence task. e.g. at 2 am in the morning.
If you use a large heap, you want to avoid using the swap at all costs. This is because the GC needs random access to the heap and as soon as one triggers which is large enough to swap, your machine will thrash for quite a long time (possibly hours), and possibly lock up. You might even have to reboot to get you machine to behave normally. (it is hard to kill a process/machine which is in such a state)

Related

Java Memory with Windows 7 or Linux

I have installed 6GB ram on my Windows and 5GB memory free space and when I run a Java program with specifying Java heap space -Xmx2048m It's working fine. My question is, what if I have this on my Linux box
cat /proc/meminfo
MemTotal: 10.130464 kB (10.1gb)
MemFree : 248.736 kB (248mb)
What will happen if I run the Java program with -Xmx2048m in Linux with this memory?
Java will allow the heap to grow to the Xmx value, but it won't necessarily start at or need to use that much. Xms specifies the minimum heap size, which is how much heap memory Java will allocate right at the start. Java will allocate additional memory for Perm Gen. Any program, not just Java, will begin to fail if it needs more memory when there is none available. Java in particular throws OutOfMemoryError when either Xmx is reached or there is no available memory on the machine.
MemFree is the amount of physical memory left, but that is not the total amount of available memory. When physical memory is full, the operating system will use swap space (SwapTotal and SwapFree). Swap space is usually on the hard disk and therefore very slow. Linux would try to keep the most frequently used memory blocks in physical memory to maintain performance, but usually there is some slowdown. It's likely the Linux box is already using some swap space considering there is a relatively small amount of free physical space left. Combine MemFree and SwapFree to get your total available memory.
Edit: With 1.8GB total physical plus swap free, you would be able to start Java because it initially uses Xms (min heap) plus PermGen memory, which defaults to 220MB on 10GB of physical ram (1/64 physical memory plus 64MB PermGen). As your program runs, it could use the rest of your available system memory, but only if your program actually needs it. If this program is not resource intensive, it will likely stay in the lower end. Typically you should set Xmx so that it doesn't use all your memory though. You may want to just close some other programs if your memory usage is that high.

JVM heap space allocation is confusing

I have a java application running with a max heap size of 8 GB .
On a 32 GB memory, the slice of Old gen was 7.4 GB(approx) . In a 128 GB memory, the same application gets a slice of Old Gen of 6.2 GB(approx).
I would like to know how this is done by the JVM internally? Is there a math that it uses. Actually , am in the phase of GC tuning and would be helpful if I get to know how this number is arrived by default. I use JDK 1.7.
It does not have to do with the total RAM in the system. The GC ratios affect how much memory can exist in various regions.
-XX:NewRatio=n Ratio of old/new generation sizes. The default value is 2.
-XX:SurvivorRatio=n Ratio of eden/survivor space size. The default value is 8.
-XX:MaxHeapFreeRatio=70 Maximum percentage of heap free after GC to avoid shrinking.
Use the first 2 ratios to tweak the ratio of the heap internally within the VM itself. Use the free heap ratios to tweak the amount of memory that the heap can grow / shrink by.
Recommended reading - Oracle provided GC tuning guide.

Java 32bit Xmx vs java 64bit Xmx

I am really confused with this.
Xmx according to the java docs, is the maximum allowable heap size.
Xms is the minimum required java heap size, and is allocated at JVM start.
On a 32 bit JVM (4GB ram), java -Xmx1536M HelloWorld gives a cannot allocate enough memory error.
On a 64 bit JVM (4GB Ram), java -Xmx20G HelloWorld works just fine. But I don't even have that much virtual or physical memory allocated.
So from this, I conclude that Java 32 bit is allocating the 1536M at JVM startup, but Java 64 bit is not.
Why? A simple Hello World should not need 1536M to run. I am just specifying that 1536M is the maximum, not that it is needed.
Explanations anyone?
There is a distinction between allocating the memory and allocating the address space. The Oracle JVM is allocating the address space on startup to ensure the heap is contiguous. This allows for certain optimizations to be used with the heap.
If the allocation fails, then Java won't start... as you have seen. It isn't necessarily using that much memory, but it is allocating the required address space up-front. Since you are passing -Xmx1536m, it is saying ok, I need to allocate that in case you need it... and since it must be contiguous it does it up-front so it can guarantee it (or fails trying).
This behavior is the same on both 32-bit and 64-bit JVMs. What you are seeing is the 2GB per-process address space limitation of 32-bit processes (at least, on Windows this is the limitation - it may be slightly larger on other platforms) causing this allocation to fail on 32-bit, where 64-bit has no issues since it has much larger address space. But, you say, 1536m is less than 2GB, I should be good, right? Not quite - the heap is not the only thing being allocated in the address space, DLLs and other stuff is also allocated in the address space...so getting a contiguous 1536m chunk out of 2GB max on 32-bit is unfortunately very unlikely. I've seen values below 1000m fail on 32-bit processes with particularly bad fragmentation, and usually 1200-1300m is the max heap you can specify on 32-bit.
On modern OSes, ASLR (Address Space Layout Randomization) makes fragmentation of 32-bit process address space worse. It intentionally loads DLLs into random addresses for security reasons... making it even less likely you can get a big, contiguous heap in 32-bit.
In 64-bit, the address space is so large that fragmentation is no longer a problem and giant heaps can be allocated without issues. Even if you have 4GB of RAM on 32-bit, though, the 2GB per process address space limitation (at least on Windows) usually means the max heap is usually only 1300m or so.
Actually, the application is not allocating the Xmx memory at startup.
The -Xms parameter configure the startup memory. (What are the Xms and Xmx parameters when starting JVMs?)
The 64bit environment allows a bigger memory allocation then 32bits. But, in fact, it's using the HD space, not the memory ram.
See this other post for more info.
Estimating maximum safe JVM heap size in 64-bit Java
Under Windows there is a difference in memory allocation operations with native WinAPI low-level functions like VirtualAlloc.
"Reserving" means allocation of a continuous area within process' address space without actually making this area of virtual memory usable. Allocated area is not backed by actual physical RAM or swap space and does not consume any free memory. Any application can reserve any amount of address space limited only by processor's memory addressing capability (bitness).
"Committing" means backing some of previously "reserved" memory with real memory - RAM or swap space, making it actually readable/writable by the process. This memory is taken from available OS virtual memory pool (RAM and swap).
An alternative to "committing" memory (taking a blank page from the pool) is "mapping" a file into the previously "reserved" memory. This does not consume memory from the swap pool but uses the mapped file in a manner similar to a dedicated swap space for that specific region of a process' address space.
Native Windows applications (like JVM itself) reserve memory for all heaps needed in the future, but commit it only as needed.
High-level memory operations like malloc() style functions or "new" operators really do "commits" as needed or even do their own heap management logic user-mode with memory committed ahead by large chunks as it is'a CPU-intensive kernel call and works at page (4k) granularity.
During process startup JVM "reserves" -Xmx memory, but "commits" only -Xms amount of it. The remaining reserved memory is committed on demand as heaps grow. So heaps can grow up to available memory or -Xmx parameter, whichever is smaller.

Why is my JVM's total memory usage more than 30 times greater than its Xmx value?

I am running a Java application with a maximum heap size of 128 MB (-Xmx128M). It is running to successful completion with no OutOfMemoryError, or any other unhandled exception. Therefore, I am assuming that its actual heap size did stay within the declared limit of 128 MB.
However, when observing the process for this Java application, I am seeing a peak total memory usage of 4,188,548 KB (~4 GB). This is a growth of more than 30 times the controlled maximum size of the heap. Although I understand that this value includes virtual memory allocated that may be significantly greater than the actual physical memory used, it affects hard limits such as those imposed by Sun Grid Engine, and therefore it is meaningful.
How exactly is this possible? I understand that the total memory consumed by the JVM includes quite a bit more than the size of the heap, but I do not understand how it could need several GB of extra memory beyond what the application actually needs to create its objects and perform its computation.
I am using Sun Java 1.6.0.31, on a 64-bit RHEL Linux distribution.
There are several memory sinks besides the Java heap controlled by -Xmx:
Thread stacks
PermGen space
direct ByteBuffers and mapped ByteBuffer
memory allocated by native code / libraries
Without knowing details of your system I would guess, that something uses mapped ByteBuffers.
But you could dig into the issue by examing the output of the pmap command. It lists all memory regions of the process together with the filenames any region is mapped to (if the regions is mapped of course).

Tomcat memory consumption is more than heap + permgen space

I am observing a mismatch in Tomcat RAM consumption between what the OS says and what jVisualVM says.
From htop, the Tomcat JVM is has 993 MB of resident memory
From jVisualVM, the Tomcat JVM is using
Heap Max: 1,070,399,488 B
Heap Size: 298.438.656 B
Heap Used: variable, between 170MB and and 270MB
PermGen Max: 268,435,456 B
PermGen Size: 248,872,960 B
PermGen Used: slightly variable, around 150MB
From my understanding the OS memory consumption should be Heap Size + PermGen Size ~= 522 MB. But that's 471 MB less than what I'm observing.
Anyone got an idea what am I missing here?
PS: I know that my max heap is much higher than what is used, but I'm assuming that should have no effect if the JVM does not use it (i.e. Heap Size is lower).
Thanks!
Marc
From my understanding the OS memory consumption should be Heap Size + PermGen Size ~= 522 MB. But that's 471 MB less than what I'm observing. Anyone got an idea what am I missing here?
If I understand the question what you are seeing is a combination of memory fragmentation and JVM memory overhead in other areas. We often see 2 times the memory usage for our production programs than we would expect to see from our memory settings.
Memory fragmentation can mean that although the JVM thinks that the OS has given it some number of bytes, there is a certain addition number of bytes that had to be given because of memory subsystem optimizations.
In terms of JVM overhead, there are a number of other storage areas that are not included in the standard memory configs. Here's a good discussion about this. To quote:
The following
are examples of things that are not part of the garbage collected heap
and yet are part of the memory required by the process:
Code to implement the JVM
The C manual heap for data structures implementing the JVM
Stacks for all of the threads in the system (app + JVM)
Cached Java bytecode (for libraries and the application)
JITed machine code (for libraries and the application)
Static variables of all loaded classes
The first thing we have to bear in mind is that: JVM process heap (OS process) = Java object heap + [Permanent space + Code generation + Socket buffers + Thread stacks + Direct memory space + JNI code + JNI allocated memory + Garbage collection], where in this "collection" permSpace is usually the bigest chunk.
Given that, I guess the key here is the JVM option -XX:MinFreeHeapRatio=n, where n is from 0 to 100, and it specifies that the heap should be expanded if less than n% of the heap is free. It is usually 40 by default (Sun), so when the JVM allocates memory, it gets enough to get 40% free (this is not applicable if you have -Xms == -Xmx). Its "twin option", -XX:MaxHeapFreeRatio usually defaults to 70 (Sun).
Therefore, in a Sun JVM the ratio of living objects at each garbage collection is kept within 40-70%. If less than 40% of the heap is free after a GC, then the heap is expanded. So assuming you are running a Sun JVM, I would guess that the size of the "java object heap" has reached a peak of about 445Mb, thus producing an expanded "object heap" of about 740 Mb (to guarantee a 40% free). Then, (object heap) + (perm space) = 740 + 250 = 990 Mb.
Maybe you can try to output GC details or use jconsole to verify the evolution of the heap size.
P.S.: when dealing with issues like this, it is good to post OS and JVM details.
During the startup of your application the JVM will reserve memory equal to roughly the size of your Heap Max value (-Xmx) plus a bit more for other stuff. This prevents the JVM from having to go back to the OS to reserve more memory later.
Even if your application is only using 298mb of heap space, there will still be the 993mb reserved with the OS. You will need to read more into reserved vs committed memory.
Most of the articles you will read when talking about garbage collection will refer to allocation from a heap perspective and not the OS level. By reserving the memory at start-up for your application, the garbage collection can work in its own space.
If you need more details, read the article Tuning Garbage Collection
Here are some important exerts from the document
At initialization, a maximum address space is virtually reserved but
not allocated to physical memory unless it is needed.
Also look at section 3.2 (iv) in the document
At initialization of the virtual machine, the entire space for the
heap is reserved. The size of the space reserved can be specified with
the -Xmx option. If the value of the -Xms parameter is smaller than
the value of the -Xmx parameter, not all of the space that is reserved
is immediately committed to the virtual machine.
The OS will report the memory used by the JVM + the memory used by your program. So it will always be higher than what the JVM reports as memory usage. There is a certain amount of memory need by the JVM itself in order execute your program and the OS can't tell the difference.
Unfortunately using the system memory tools isn't a very precise way to track your programs memory consumption. JVM's typically allocate large blocks of memory so object creation is quick, but it doesn't mean your program is consuming that memory.
A better way of knowing what your program is actually doing is to run jconsole and look at the memory usage there. That's a very simple tool for looking at memory that's easy to set up.

Categories