How does Java reserve/use memory? - java

This is probably a noob question, but I need to run a java application processing a large dataset. So I went about -Xmx14G, knowing that my machine has 16G of physical memory.
A short while later, boom, I am being notified by my operating system that my startup disk is almost full. I checked my process, there's no OOM exception, just that it stalled. Checked my activity monitor, doesn't says the application runs at full memory capacity.
How does the JVM reserves/use memory?

Typically, the JVM allocates new memory until the heap is full, in which case it garbage collects, freeing up non-referenced objects. If you allocated 14GB for the heap, chances are it will consume that much memory.

There is another JVM argument -Xms<size> it' initial heap size. If we do not set it explicitly JVM will choose one automatically depending on PC configuration. This value is never that big, typically 64M. Later JVM may allocate more memory up to max. But it happens only when the app really uses it. If actual memory usage decreases JVM will shrink the memory to a smaller size.

Related

Java not releasing unused heap memory

I am facing an issue where my Java application heap increases with an increased no. of requests to the application but then it does not release even the unused heap memory.
Here is the description:
My java application starts with a heap memory of 200MB out of which around 100MB is in use.
As the no. of requests increases, the heap memory usage goes up to 1GB.
Once the requests processing is finished, the used heap memory drops back to normal but the unused/free heap space remains 1GB.
I have tried to use -XX:-ShrinkHeapInSteps, -XX:MinHeapFreeRatio and -XX:MaxHeapFreeRatio JVM arguments but was not able to solve this.
Note: If I try to run the Garbage Collector manually then it lowers the unused heap memory also.
Please suggest how we can lower the unused heap memory.
The used heap will not return if the -Xms is high. -Xms essentially overrides the FreeRation. Now there are other factors to consider, in the case of parallel GC you can't shrink the heap as parallel GC doesn't allow that.
Also, JVM can only relinquish the memory after the fullGC if parallelGC is not used.
So essentially, not much can be done here. The JVM doesn't relinquish the memory to OS to avoid recreating the memory. Memory allocation is expensive work, so JVM will hold on to that memory for some time and as the memory management is controlled by Java, it is not always possible to force things here.
One downside of reducing heap size would be, it will take time for Java to recreate the memory space over and over with incoming requests. So the clients will always see some higher latency. However, if the memory space is already created, the next stream of clients will see lower latency so essentially your amortized performance will increase.

Doesn't the jvm argument xms mean process won't start if the specified memory is missing?

I had set the xms to 32g and xmx to 32g
The program started, but when around 25GB data was loaded into memory, the process was killed by Linux, giving the reason of memory issues.
If 32g was already assigned to the process due to xms being 32g, why did it went out of memory?
Doesn't xms mean allocate this memory in beginning and if you cannot please don't start the process ?
Can someone please explain, why programs fails ?
"Allocating memory" really means "allocating virtual address space". Modern operating systems separate the address space used by a process from physical memory.
So, with -Xms32G, you've got 32G of address space.
Actual memory is allocated in pages and on demand, which generally means that something has to actually 'touch' a page before memory is 'committed' to the page.
Thus in reality, memory is only being committed as needed. And if the OS decides it is under real-memory pressure at the time, you're likely to get killed.
You can force the JVM to touch each page at startup by using the JVM option -XX:+AlwaysPreTouch. The likely effect of this will be that the JVM process starts and gets killed during its initialization, before your program is entered at main(). You still can't get the memory, you just find out sooner.
The OOM killer being what it is, it is also possible that the pretouch will go ok, your code will run, but at some later time due to other system activity, the kernel will decide it's critically low on available resources, and since you're probably the largest process around, there's a target on your back.
First of all -Xms and -Xmx control the heap of your java process. A java process need memory for other things too, like off heap allocation, GC structures, etc. What this means is that when you set your application to a heap of 1GB, your java process is going to need more than that.
Second point is that -Xms controls the committed memory in the virtual space. Virtual space for a 64 bit CPU is huge. Committed memory becomes resident in a lazy fashion (resident is actual in RAM, for example). So when you set -Xmx and -Xms, you will get a portion of virtual memory allocated as needed.
You should carefully read the logs on this part:
giving the reason of memory issues
you probably are killed by the OOM Killer, which kills the process, which you already know (from the above) that needs more than the heap.
If you want to allocate memory and make it resident, add the -XX:+AlwaysPreTouch flag. This will make your process start a lot slower though and in general, is not a great idea. It has its benefits in various applications.

Understanding JVM Memory Allocation and Java Out of Memory: Heap Space

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

-Xmx attribute and available system memory correlation

I have a question on my mind. Let's assume that I have two parameters passed to JVM:
-Xms256mb -Xmx1024mb
At the beginning of the program 256MB is allocated. Next, some objects are created and JVM process tries to allocate more memory. Let's say that JVM needs to allocate 800MB. Xmx attribute allows that but the memory which is currently available on the system (let's say Linux/Windows) is 600MB. Is it possible that OutOfMemoryError will be thrown? Or maybe swap mechanism will play a role?
My second question is related to the quality of GC algorithms. Let's say that I have jdk1.5u7 and jdk1.5u22. Is it possible that in the latter JVM the memory leaks vanish and OutOfMemoryError does not occur? Can the quality of GC be better in the latest version?
The quality of the GC (barring a buggy GC) does not affect memory leaks, as memory leaks are an artifact of the application -- GC can't collect what isn't actual garbage.
If a JVM needs more memory, it will take it from the system. If the system can swap, it will swap (like any other process). If the system can not swap, your JVM will fail with a system error, not an OOM exception, because the system can not satisfy the request and and this point its effectively fatal.
As a rule, you NEVER want to have an active JVM partially swapped out. GC event will crush you as the system thrashes cycling pages through the virtual memory system. It's one thing to have a idle background JVM swapped out as a whole, but if you machine as 1G of RAM and your main process wants 1.5GB, then you have a major problem.
The JVM like room to breathe. I've seen JVMs in a GC death spiral when they didn't have enough memory, even though they didn't have memory leaks. They simply didn't have enough working set. Adding another chunk of heap transformed that JVM from awful to happy sawtooth GC graphs.
Give a JVM the memory it needs, you and it will be much happier.
"Memory" and "RAM" aren't the same thing. Memory includes virtual memory (swap), so you can allocate a total of free RAM+ free swap before you get the OutOfMemoryError.
Allocation depends on the used OS.
If you allocate too much memory, maybe you could end up having loaded portions into swap, which is slow.
If the your program runs fater os slower depends on how VM handle the memory.
I would not specify a heap that's not so big to make sure it don't occupy all the memory preventing the slows from VM.
Concerning your first question:
Actually if the machine can not allocate the 1024 MB that you asked as max heap size it will not even start the JVM.
I know this because I noticed it often trying to open eclipse with large heap size and the OS could not allocate the larger heap space the JVM failed to load. You could also try it out yourself to confirm. So the rest of the details are irrelevant to you. If course if your program uses too much swap (same as in all languages) then the performance will be horrible.
Concerning your second question:
the memory leaks vanish
Not possible as they are bugs you will have to fix
and OutOfMemoryError does not occur? Can the quality of GC be better
in the latest version?
This could happen, if for example some different algorithm in GC is used and it manages to kick-in before you seeing the exception. But if you have a memory leak then it would probable mask it or you would see it intermittent.
Also various JVMs have different GCs you can configure
Update:
I have to admit (after see #Orochi note) that I noticed the behavior on max heap on Windows. I can not say for sure that this applies to linux as well. But you could try it yourself.
Update 2:
As an answer to comments of #DennisCheung
From IBM(my emphasis):
The table shows both the maximum Java heap possible and a recommended limit for the maximum Java heap size setting ......It is important to have more physical memory than is required by all of the processes on the machine combined to prevent paging or swapping. Paging reduces the performance of the system and affects the performance of the Java memory management system.

vm size (task manager) vs. heap size java application

I want to find a memory leak in a Java 1.5 application. I use JProfiler for profiling.
I see using the windows' task manager that the vm size for my application is about 790000KB (increased from approx 300000KB). In the profiler I see that that the allocated heap is 266MB (increasing also).
Probably it's a rookie question but, what else can occupy so much memory besides the heap so that it goes to approx 700MB vm size (or private bytes size)?
I mention that there are approx 1200 threads running, which can occupy, according to an answer from here quite some memory, but I think there still is some space until 700MB. By the way, how I can see how much memory the threads stacks occupy?
Thanks.
The JVM can use alot of virtual memory which may not use resident memory. On startup it allocates the heap, and maps in its shared libraries. Classes which are loaded use Perm Gen space. An application can use direct memory which can be as large as the heap maximum. As each thread is created a stack is allocated for each thread. In each case until this memory is used, it might not be allocated to the application i.e. not use physical memory. As the application warms up, more of the virtual memory can become physical memory.
If you believe your JVM is not running efficiently, the first thing I would try is Java 6 which has had many fixes and improvements since the last release of Java 5.0.

Categories