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.
Related
I'm looking into really understanding how memory allocation works in the JVM.
I'm writing an application in which I'm getting Out of Memory: Heap Space exceptions.
I understand that I can pass in VM arguments such as Xms and Xmx to up the heap space that the JVM allocates for the running process. This is one possible solution to the problem, or I can inspect my code for memory leaks and fix the issue there.
My questions are:
1) How does the JVM actually allocate memory for itself? How does this relate to how the OS communicates available memory to the JVM? Or more generally, how does memory allocation for any process actually work?
2) How does virtual memory come into play? Let's say you have a system with 32GB of physical memory and you allocate all 32GB to your Java process. Let's say that your process actually consumes all 32GB of memory, how can we enforce the process to use virtual memory instead of running into OOM exceptions?
Thanks.
How does the JVM actually allocate memory for itself?
For the heap it allocate one large continuous region of memory of the maximum size. Initially this is virtual memory however, over time it becomes real memory for the portions which are used, under control of the OS
How does this relate to how the OS communicates available memory to the JVM?
The JVM has no idea about free memory in the OS.
Or more generally, how does memory allocation for any process actually work?
In general it uses malloc and free.
How does virtual memory come into play?
Initially virtual memory is allocated and this turns into real memory as used. This is normal for any process.
Let's say you have a system with 32GB of physical memory and you allocate all 32GB to your Java process.
You can't. The OS need some memory and there will be memory for other purposes. Even within the JVM the heap is only a portion of the memory used. If you have 32 GB of memory I suggest as 24 GB heap max.
Let's say that your process actually consumes all 32GB of memory,
Say you have 48 GB and you start a process which uses 32 GB of main memory.
how can we enforce the process to use virtual memory instead of running into OOM exceptions?
The application uses virtual memory right from the start. You cannot make the heap too large because if it starts swapping your machine (not just your application) will become unusable.
You can use more memory than you have physical by using off heap memory, carefully. However managed memory must be in physical memory so if you need a 32 GB heap, buy 64 GB of main memory.
The JVM (or for that matter any process) that wants to allocate memory will call the C runtime 'malloc' function. This function maintains the heap memory of the C runtime. It, in turn, obtains memory from the operating system kernel - the function used for this is platform dependent; in Linux it could be using the brk or sbrk system calls.
Once the memory has been obtained by the JVM, it manages the memory itself, allocating parts of it to the various objects created by the running program.
Virtual memory is handled entirely by the operating system kernel. The kernel manages mapping of physical memory pages to the address space of various processes; if there is less physical memory than is needed by all the processes in the system then the OS Kernel will swap some of it out to disk.
You can't (and don't need to) force processes to use Virtual Memory. It is transparent to your process.
If you are getting 'out of memory' errors, then the causes are likely to be:
The JVM limits are being exceeded. These are controlled by various command line arguments and/or properties as you stated in your question
The OS may have run out of swap space (or not have any swap space configured to start with). Or some OSs don't even support virtual memory, in which case you have run out of real memory.
Most OSs have facilities for the administrator to limit the amount of memory consumed by a process - for example, in Linux the setrlimit system call and/or the ulimit shell command, both of which set limits that the kernel will observe. If a process requests more memory than is allowed by the limits, then the attempt will fail (typically this results in an out of memory message).
This blog looks at Java memory utilisation which you might find useful:
http://www.waratek.com/blog/november-2013/introduction-to-real-world-jvm-memory-utilisation
The JVM allocates Java heap memory from the OS and then manages the
heap for the Java application. When an application creates a new
object, the JVM sub-allocates a contiguous area of heap memory to
store it. An object in the heap that is referenced by any other object
is "live," and remains in the heap as long as it continues to be
referenced. Objects that are no longer referenced are garbage and can
be cleared out of the heap to reclaim the space they occupy. The JVM
performs a garbage collection (GC) to remove these objects,
reorganizing the objects remaining in the heap.
Source: http://pubs.vmware.com/vfabric52/index.jsp?topic=/com.vmware.vfabric.em4j.1.2/em4j/conf-heap-management.html
In a system using virtual memory, the physical memory is divided into
equally-sized pages. The memory addressed by a process is also divided
into logical pages of the same size. When a process references a
memory address, the memory manager fetches from disk the page that
includes the referenced address, and places it in a vacant physical
page in the RAM.
Source: http://searchstorage.techtarget.com/definition/virtual-memory
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.
I am using 64-bit Linux and Java JVM. I want to confirm if the memory used by JVM is smaller than physical memory size of the machine, there will be no disk memory swap by OS?
No, that's not necessarily true. Physical memory is shared by all processes, as well as by a bunch of other kernel things (e.g. the disk cache). So the amount of virtual memory used by your application is not the only consideration.
You can start your java application with the jvm argument -Xmx512m wich will tell the jvm to use a max of 512MB of ram for your heap. Take in account also that there exists another parameter for thread stack size -Xss512k. So the amount of memory that your jvm will use will be the max heap + (threadCount * threadStackSize) + some more ram for JIT compilation and GC datastructures depending on the GC collector that you use
Having this into account you can make sure your jvm wont use more ram than what is present in your machine
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)
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.