Speed tradeoff of Java's -Xms and -Xmx options - java

Given these two commands
A:
$ java -Xms10G -Xmx10G myjavacode input.txt
B:
$ java -Xms5G -Xmx5G myjavacode input.txt
I have two questions:
Since command A reserves more memory with its parameters, will A run faster than B?
How do -Xmx and -Xms affect the running process and the output of my program?

The -Xmx argument defines the max memory size that the heap can reach for the JVM. You must know your program well and see how it performs under load and set this parameter accordingly. A low value can cause OutOfMemoryExceptions or a very poor performance if your program's heap memory is reaching the maximum heap size. If your program is running in dedicated server you can set this parameter higher because it wont affect other programs.
The -Xms argument sets the initial heap memory size for the JVM. This means that when you start your program the JVM will allocate this amount of memory instantly. This is useful if your program will consume a large amount of heap memory right from the start. This avoids the JVM to be constantly increasing the heap and can gain some performance there. If you don't know if this parameter is going to help you, don't use it.
In summary, this is a compromise that you have to decide based only in the memory behavior of your program.

It depends on the GC your java is using. Parallel GCs might work better on larger memory settings - I'm no expert on that though.
In general, if you have larger memory the less frequent it needs to be GC-ed - there is lots of room for garbage. However, when it comes to a GC, the GC has to work on more memory - which in turn might be slower.

I have found that in some cases too much memory can slow the program down.
For example I had a hibernate based transform engine that started running slowly as the load increased. It turned out that each time we got an object from the db, hibernate was checking memory for objects that would never be used again.
The solution was to evict the old objects from the session.
Stuart

Allocation always depends on your OS. If you allocate too much memory, you could end up having loaded portions into swap, which indeed is slow.
Whether your program runs slower or faster depends on the references the VM has to handle and to clean. The GC doesn't have to sweep through the allocated memory to find abandoned objects. It knows it's objects and the amount of memory they allocate by reference mapping. So sweeping just depends on the size of your objects. If your program behaves the same in both cases, the only performance impact should be on VM startup, when the VM tries to allocate memory provided by your OS and if you use the swap (which again leads to 1.)

The speed tradeoffs between various settings of -Xms and -Xmx depend on the application and system that you run your Java application on. It also depends on your JVM and other garbage collection parameters you use.
This question is 11 years old, and since then the effects of the JVM parameters on performance have become even harder to predict in advance. So you can try different values and see the effects on performance, or use a free tool like Optimizer Studio that will find the optimal JVM parameter values automatically.

It is difficult to say how the memory allocation will affect your speed. It depends on the garbage collection algorithm the JVM is using. For example if your garbage collector needs to pause to do a full collection, then if you have 10 more memory than you really need then the collector will have 10 more garbage to clean up.
If you are using java 6 you can use the jconsole (in the bin directory of the jdk) to attach to your process and watch how the collector is behaving. In general the collectors are very smart and you won't need to do any tuning, but if you have a need there are numerous options you have use to further tune the collection process.

> C:\java -X
-Xmixed mixed mode execution (default)
-Xint interpreted mode execution only
-Xbootclasspath:<directories and zip/jar files separated by ;>
set search path for bootstrap classes and resources
-Xbootclasspath/a:<directories and zip/jar files separated by ;>
append to end of bootstrap class path
-Xbootclasspath/p:<directories and zip/jar files separated by ;>
prepend in front of bootstrap class path
-Xnoclassgc disable class garbage collection
-Xincgc enable incremental garbage collection
-Xloggc:<file> log GC status to a file with time stamps
-Xbatch disable background compilation
-Xms<size> set initial Java heap size
-Xmx<size> set maximum Java heap size
-Xss<size> set java thread stack size
-Xprof output cpu profiling data
-Xfuture enable strictest checks, anticipating future default
-Xrs reduce use of OS signals by Java/VM (see documentation)
-Xcheck:jni perform additional checks for JNI functions
-Xshare:off do not attempt to use shared class data
-Xshare:auto use shared class data if possible (default)
-Xshare:on require using shared class data, otherwise fail.
The -X options are non-standard and subject to change without notice.
(copy-paste)

This was always the question I had when I was working on one of my application which created massive number of threads per request.
So this is a really good question and there are two aspects of this:
1. Whether my Xms and Xmx value should be same
- Most websites and even oracle docs suggest it to be the same. However, I suggest to have some 10-20% of buffer between those values to give heap resizing an option to your application in case sudden high traffic spikes OR a incidental memory leak.
2. Whether I should start my Application with lower heap size
- So here's the thing - no matter what GC Algo you use (even G1), large heap always has some trade off. The goal is to identify the behavior of your application to what heap size you can allow your GC pauses in terms of latency and throughput.
- For example, if your application has lot of threads (each thread has 1 MB stack in native memory and not in heap) but does not occupy heavy object space, then I suggest have a lower value of Xms.
- If your application creates lot of objects with increasing number of threads, then identify to what value of Xms you can set to tolerate those STW pauses. This means identify the max response time of your incoming requests you can tolerate and according tune the minimum heap size.

Related

Is it possible to fix OutOfMemory error by specify GC flags?

Is specifying GC flags a possible solution to OutOfMemory exceptions, or does it have no impact or whether the program will run out of memory?
The GC flags in question are: -XX:+UseConcMarkSweepGC and -XX:+CMSIncrementalMode
I'm asking because I thought the above flags (and GC flags in general) are there to tune JVM performance (in relation to it's response/speed), but they have no impact on reducing the minimum memory requirements of your program. In other words, if there is not enough memory for the program to run to completion (e.g. running into OutOfMemory exception), no amount of JVM tuning will resolve that.
If you get OutOfMemoryError: heap space, there is nothing you can do. JVM will never throw this before GCing the last byte out of the heap.
However, if you get OutOfMemoryError: GC overhead limit exceeded, then there may be something you can still do about it because this is a "soft" error and there may be a config setting that will lessen the GC overhead. Quite improbable, I must add, but at least possible in theory.
The only tuning parameter which matters is the maximum memory. i.e. -Xmx or -mx If your program has run out of memory due to a memory leak, even raising this won't help.
BTW: Setting memory tuning can actually reduce the amount of memory you can use before you run out. E.g. if you set the NewSize, this can limit how much the JVM can resize the generations to use all the memory.
In general, the less options you use the better if you want to use all your memory.
If there is memory leak in your code, those flags are not useful.
As per Virtual Machine Garbage Collection Tuning:
Unless your application has rather strict pause time requirements, first run your application and allow the VM to select a collector. If necessary, adjust the heap size to improve performance. If the performance still does not meet your goals, then use the following guidelines as a starting point for selecting a collector.
If the application has a small data set (up to approximately 100MB), then
select the serial collector with -XX:+UseSerialGC.
If the application will be run on a single processor and there are no pause time requirements, then
let the VM select the collector, or
select the serial collector with -XX:+UseSerialGC.
If (a) peak application performance is the first priority and (b) there are no pause time requirements or pauses of one second or longer are acceptable, then
let the VM select the collector, or
select the parallel collector with -XX:+UseParallelGC and (optionally) enable parallel compaction with -XX:+UseParallelOldGC.
If response time is more important than overall throughput and garbage collection pauses must be kept shorter than approximately one second, then
select the concurrent collector with -XX:+UseConcMarkSweepGC. If only one or two processors are available, consider using incremental mode, described below.

-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.

Does the JVM force garbage collection when it reaches its -Xmx limit?

The question is basically contained in the title.
Say you have an application that has reached its JVM -Xmx limit. When that application requires more memory is garbage collection forced ? (in the HotSpot JVM)
A second odd thing I can't explain is that I currently have an application server which is ran with -Xmx=2048m, the "top" command (on linux) reports 2.7g for its process.
So how/when is an application allowed to exceed its -Xmx ?
Thanks,
Actually the normal GC is triggered when young generation is full (not the whole heap) and major GC is triggered when there is no space left in survivor space so some objects need to be migrated to old generation.
The Xmx parameter does only specify the size of the heap. The Java process takes more memory since the heap is only one part of the Java process, I guess you also have other stuff that the java process contains like native libraries, the perm gen and also native memory allocations made by the application.
Here's an nice article describing memory allocation:
http://www.ibm.com/developerworks/java/library/j-nativememory-linux/
Yes, the JVM will certainly call the GC if it reaches the heap limit (and probably much sooner). If this doesn't help, it will throw OutOfMemoryErrors.
The reason why you are seeing a bigger process memory consumption is that the -Xmx option only limits the Java heap space (where the Java objects are allocated on). There are several other memory regions used by the JVM additionally: space for Thread stacks, the "PermGen" (where the classes and their code is stored), "direct" memory allocated via ByteBuffers, memory allocated by native libraries, etc. For some of these additional memory regions there exist other configuration options which allow to limit them, for example -Xss, but some are even out of control of the JVM.
This is usually the case, althought GC is normally triggered much sooner, depending on the Garbage Collector you use.
Yes, if you don't still find memory it will raise OutOfmemory Error. I understand it like this.
IIRC the guarantee is that a full GC will be performed before an OutOfMemoryError is thrown. Since exceeding the heap size limit must result in such an error, that implies you'll always have at least one full GC run when the limit is reached.
Garbage collection is quite a large area, but what you say is correct for full collections (there are other types)
One thing to be aware of is that -Xmx sets the maximum heap size but there is also an -Xms, which is the minumum heap size. Your application may start with only the minimum configured. Then if the memory used reaches that, it will trigger a full garbage collection AND increase the amount of heap available, from the minimum (-Xmx) up to some value less than or equal to the maximum (-Xmx). This can happen several times, until the maximum is reached. After that, it cannot increase the heap anymore but garbage collections will continue to happen when that maximum is reached.

Java memory usage increases when App is used, but doesnt decrease when not being used

I have a java application that uses a lot of memory when used, but when the program is not being used, the memory usage doesnt go down.
Is there a way to force Java to release this memory? Because this memory is not needed at that time, I can understand to reserve a small amount of memory, but Java just reserves all the memory it ever uses. It also reuses this memory later but there must be a way to force Java to release it when its not needed.
System.gc is not working.
As pointed out in the comments, it's not certain that, while the garbage collector disposes objects, it gives back memory to the system.
Perhaps Tuning Garbage Collection Outline provides the solution to your problem:
By default the JVM grows or shrinks the heap at each GC to keep the ratio of free space to live objects at each collection within a specified range.
-XX:MinHeapFreeRatio - when the percentage of free space in a generation falls below this value the generation will be expanded to meet this percentage. Default is 40
-XX:MaxHeapFreeRatio - when the percentage of free space in a generation exceeded this value the generation will shrink to meet this value. Default is 70
Otherwise, if you suspect that you're leaking references you can figure out how, what and where objects are leaked is to monitor the heap in JVisualVM (a tool bundled with the standard SDK). You can, through this program, perform a heap-dump and get a histogram over object memory consumption:
What memory do you mean? If it is RAM (as opposed to the amount of used heap space of the Java VM itself) then this might be normal. It is a relatively expensive operation to allocate memory so once the JVM got some it is quite reluctant to give it back even if it is not needed at the time.
Have you considered using a memory profiler? If you don't have access to one, you can start with capturing a bunch of jmap -histo <pid> and writing a script to figure the differences.
System.gc has no guarantees about if it should free any memory when ran. See Why is it bad practice to call System.gc()?
Try tweaking the Xmx JVM arg down if it is set to a large value and take a look in JConsole to see what's going on with memory usage and GC activity. Normally you'd see a saw tooth pattern.
You might also want to use a profiler to see where the memory is being used and to identify any leaks.
One of two things is happening:
1) Your application is leaking references. Are you sure that you aren't hanging on to objects when you'll no longer need them? If you do, Java must maintain them in memory.
2) Java's working just fine. You get no benefit from memory that you aren't using.

Does the Sun JVM slow down when more memory is allocated via -Xmx?

Does the Sun JVM slow down when more memory is available and used via -Xmx? (Assumption: The machine has enough physical memory so that virtual memory swapping is not a problem.)
I ask because my production servers are to receive a memory upgrade. I'd like to bump up the -Xmx value to something decadent. The idea is to prevent any heap space exhaustion failures due to my own programming errors that occur from time to time. Rare events, but they could be avoided with my rapidly evolving webapp if I had an obscene -Xmx value, like 2048mb or higher. The application is heavily monitored, so unusual spikes in JVM memory consumption would be noticed and any flaws fixed.
Possible important details:
Java 6 (runnign in 64-bit mode)
4-core Xeon
RHEL4 64-bit
Spring, Hibernate
High disk and network IO
EDIT: I tried to avoid posting the configuration of my JVM, but clearly that makes the question ridiculously open ended. So, here we go with relevant configuration parameters:
-Xms256m
-Xmx1024m
-XX:+UseConcMarkSweepGC
-XX:+AlwaysActAsServerClassMachine
-XX:MaxGCPauseMillis=1000
-XX:MaxGCMinorPauseMillis=1000
-XX:+PrintGCTimeStamps
-XX:+HeapDumpOnOutOfMemoryError
By adding more memory, it will take longer for the heap to fill up. Consequently, it will reduce the frequency of garbage collections. However, depending on how mortal your objects are, you may find that how long it takes to do any single GC increases.
The primary factor for how long a GC takes is how many live objects there are. Thus, if virtually all of your objects die young and once you get established, none of them escape the young heap, you may not notice much of a change in how long it takes to do a GC. However, whenever you have to cycle the tenured heap, you may find everything halting for an unreasonable amount of time since most of these objects will still be around. Tune the sizes accordingly.
If you just throw more memory at the problem, you will have better throughput in your application, but your responsiveness can go down if you're not on a multi core system using the CMS garbage collector. This is because fewer GCs will occur, but they will have more work to do. The upside is that you will get more memory freed up with your GCs, so allocation will continue to be very cheap, hence the higher througput.
You seem to be confusing -Xmx and -Xms, by the way. -Xms just sets the initial heap size, whereas -Xmx is your max heap size.
More memory usually gives you better performance in garbage collected environments, at least as long as this does not lead to virtual memory usage / swapping.
The GC only tracks references, not memory per se. In the end, the VM will allocate the same number of (mostly short-lived, temporary) objects, but the garbage collector needs to be invoked less often - the total amount of garbage collector work will therefore not be more - even less, since this can also help with caching mechanisms which use weak references.
I'm not sure if there is still a server and a client VM for 64 bit (there is for 32 bit), so you may want to investigate that also.
According to my experience, it does not slow down BUT the JVM tries to cut back to Xms all the time and try to stay at the lower boundary or close to. So if you can effort it, bump Xms as well. Sun is recommending both at the same size. Add some -XX:NewSize=512m (just a made up number) to avoid the costly pile up of old data in the old generation with leads to longer/heavier GCs on the way. We are running our web app with 700 MB NewSize because most data is short-lived.
So, bottom line: I do not expect a slow down, but put your more of memory to work. Set a larger new size area and set Xms to Xmx to lower the stress on the GC, because it does not need to try to cut back to Xms limits...
It typically will not help your peformance/throughput,if you increase -Xmx.
Theoretically there could be longer "stop the world" phases but in practice with the CMS that's not a real problem.
Of course you should not set -Xmx to some insane value like 300Gbyte unless you really need it :)

Categories