My maths says the following Java program would need approx 8GB (2147483645 * 4 bytes) of RAM:
package foo;
public class Foo {
public static void main(String[] args) throws Exception {
int[] arr = new int[Integer.MAX_VALUE-2];
Thread.sleep(500000L);
}
}
This is backed up by observing the program when running:
But unless you set the max heap to around 12.5GB, the program fails to start:
$ java -Xmx12000m -cp ./ foo.Foo
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at foo.Foo.main(Foo.java:5)
$ java -Xmx12500m -cp ./ foo.Foo
//this works
Can understand the need for a bit of wiggle-room but why do we need so much?
Its because of the MinHeapFreeRatio default value (which is 40%). If you want to "need" less then you have to specify it: e.g. 5%
-XX:MinHeapFreeRatio=5
Also, you need to change memory allocated to the young generation as it plays a important role in memory allocation:
After total available memory, the second most influential factor affecting garbage collection performance is the proportion of the heap dedicated to the young generation.
try this:
java -Xmx9g -XX:MinHeapFreeRatio=1 -XX:MaxNewSize=256m -cp ./ foo.Foo
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/sizing.html
Related
I have a spring batch application, it consumes ~16GB Memory & 75% of CPU(4core X2.5Ghz) and at times it throws out of memory exception.
I want to optimize the Heap allocation & Garbage collection and tried with the following JVM options so resolve the out of memory exception.
I could not understand some of these parameters as I copy pasted directly from an article
JAVA_OPTS="-server -Xmx20480m -Xms512m -XX:+UseConcMarkSweepGC
-XX:+UseParNewGC -XX:+CMSClassUnloadingEnabled -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=30 -XX:+CMSIncrementalMode -XX:+CMSIncrementalPacing -XX:ParallelCMSThreads=2 -XX:+UseCMSCompactAtFullCollection -XX:+DisableExplicitGC -XX:MaxHeapFreeRatio=70 -XX:MinHeapFreeRatio=40 -XX:MaxTenuringThreshold=0 -XX:NewSize=450m -XX:MaxNewSize=650m"
would it really optimize the Heap allocation & Garbage collection and resolve the out of memory exception.?
First, you need to take a heap dump of the process when it is throwing the OOM error. You can do that by adding -XX:+HeapDumpOnOutOfMemoryError JVM option. After when you have the heap dump try using any of the following tool to analyze your heap dump. Locate which object is growing in the memory and then optimize it. Heap dump analyze tools are :
Eclipse Memory Analyzer
Heap Hero
jxray
This error is usually thrown when there is insufficient space to allocate an object on the Java heap or if the Java process is spending more than 98% of its time doing garbage collection and if it is recovering less than 2% of the heap and has been doing so far the last 5 garbage collection cycles.
I would first use a Java profiler to determine what methods are allocating large numbers of objects on the heap and make sure that they are no longer referenced after they are not needed. If this doesn't fix the issue and I have confirmed that I need all the objects, the other option would be to increase the max heap size of the program.
This could also happen when you are using too many 'String' objects or updating those strings again and again.
Strings are stored in a hashed string pool, which resides in the Heap space. When you manipulate a string, a new string is formed and stored in a different pool (hashed pools) but the original string is not deleted until the garbage collector does it.
If we use StringBuilder or StringBuffer (both are mutable, unlike strings), the space is better utilised.
Read more about strings immutability and why stringbuilder should be preferred when you need a lot of string manipulations to be performed.
StringBuilder-StringBuffer-Strings in java
Why strings are immutable in java?
I am mass-processing very large files. I am calling the following method on each URI in each line:
public String shortenUri(String uri) {
uri = uri
.replace("http://www.lemon-model.net/lemon#", "lemon:")
.replace("http://babelnet.org/rdf/", "bn:")
.replace("http://purl.org/dc/", "dc:")
.replace("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "rdf:");
return uri;
}
Strangely, this leads to the following error:
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.util.regex.Pattern$BnM.optimize(Pattern.java:5411)
at java.util.regex.Pattern.compile(Pattern.java:1711)
at java.util.regex.Pattern.<init>(Pattern.java:1351)
at java.util.regex.Pattern.compile(Pattern.java:1054)
at java.lang.String.replace(String.java:2239)
at XYZ.shortenUri(XYZ.java:217)
I did increase Xmsand Xmx but it did not help. Strangely, I could also not observe an increased memory usage when monitoring the process. Any suggestions on increasing the performance and memory consumption here?
A quote from Oracle:
Excessive GC Time and OutOfMemoryError
The parallel collector will throw an OutOfMemoryError if too much time is being spent in garbage collection: if more than 98% of the total time is spent in garbage collection and less than 2% of the heap is recovered, an OutOfMemoryError will be thrown. This feature is designed to prevent applications from running for an extended period of time while making little or no progress because the heap is too small. If necessary, this feature can be disabled by adding the option -XX:-UseGCOverheadLimit to the command line.
The first thing you could try is to increase the heap size even more, for example, fot a few GB with -Xmx4G.
Another option might be to prevent the creation of too many objects by not using the replace method. Instead you could create the Pattern and Matcher objects as needed (see below).
The third option I see is to disable this feature altogether with -XX:-UseGCOverheadLimit
private static final Pattern PURL_PATTERN = Pattern.compile("http://purl.org/dc/");
// other patterns
public static String shortenUri(String uri) {
// other matchers
Matcher matcher = PURL_PATTERN.matcher(uri);
return matcher.replaceAll("dc:");
}
This question already has answers here:
Why is the max recursion depth I can reach non-deterministic?
(4 answers)
Closed 5 years ago.
A simple class for demonstration purposes:
public class Main {
private static int counter = 0;
public static void main(String[] args) {
try {
f();
} catch (StackOverflowError e) {
System.out.println(counter);
}
}
private static void f() {
counter++;
f();
}
}
I executed the above program 5 times, the results are:
22025
22117
15234
21993
21430
Why are the results different each time?
I tried setting the max stack size (for example -Xss256k). The results were then a bit more consistent but again not equal each time.
Java version:
java version "1.8.0_72"
Java(TM) SE Runtime Environment (build 1.8.0_72-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.72-b15, mixed mode)
EDIT
When JIT is disabled (-Djava.compiler=NONE) I always get the same number (11907).
This makes sense as JIT optimizations are probably affecting the size of stack frames and the work done by JIT definitely has to vary between the executions.
Nevertheless, I think it would be beneficial if this theory is confirmed with references to some documentation about the topic and/or concrete examples of work done by JIT in this specific example that leads to frame size changes.
The observed variance is caused by background JIT compilation.
This is how the process looks like:
Method f() starts execution in interpreter.
After a number of invocations (around 250) the method is scheduled for compilation.
The compiler thread works in parallel to the application thread. Meanwhile the method continues execution in interpreter.
As soon as the compiler thread finishes compilation, the method entry point is replaced, so the next call to f() will invoke the compiled version of the method.
There is basically a race between applcation thread and JIT compiler thread. Interpreter may perform different number of calls before the compiled version of the method is ready. At the end there is a mix of interpreted and compiled frames.
No wonder that compiled frame layout differs from interpreted one. Compiled frames are usually smaller; they don't need to store all the execution context on the stack (method reference, constant pool reference, profiler data, all arguments, expression variables etc.)
Futhermore, there is even more race possibilities with Tiered Compilation (default since JDK 8). There can be a combination of 3 types of frames: interpreter, C1 and C2 (see below).
Let's have some fun experiments to support the theory.
Pure interpreted mode. No JIT compilation.
No races => stable results.
$ java -Xint Main
11895
11895
11895
Disable background compilation. JIT is ON, but is synchronized with the application thread.
No races again, but the number of calls is now higher due to compiled frames.
$ java -XX:-BackgroundCompilation Main
23462
23462
23462
Compile everything with C1 before execution. Unlike previous case there will be no interpreted frames on the stack, so the number will be a bit higher.
$ java -Xcomp -XX:TieredStopAtLevel=1 Main
23720
23720
23720
Now compile everything with C2 before execution. This will produce the most optimized code with the smallest frame. The number of calls will be the highest.
$ java -Xcomp -XX:-TieredCompilation Main
59300
59300
59300
Since the default stack size is 1M, this should mean the frame now is only 16 bytes long. Is it?
$ java -Xcomp -XX:-TieredCompilation -XX:CompileCommand=print,Main.f Main
0x00000000025ab460: mov %eax,-0x6000(%rsp) ; StackOverflow check
0x00000000025ab467: push %rbp ; frame link
0x00000000025ab468: sub $0x10,%rsp
0x00000000025ab46c: movabs $0xd7726ef0,%r10 ; r10 = Main.class
0x00000000025ab476: addl $0x2,0x68(%r10) ; Main.counter += 2
0x00000000025ab47b: callq 0x00000000023c6620 ; invokestatic f()
0x00000000025ab480: add $0x10,%rsp
0x00000000025ab484: pop %rbp ; pop frame
0x00000000025ab485: test %eax,-0x23bb48b(%rip) ; safepoint poll
0x00000000025ab48b: retq
In fact, the frame here is 32 bytes, but JIT has inlined one level of recursion.
Finally, let's look at the mixed stack trace. In order to get it, we'll crash JVM on StackOverflowError (option available in debug builds).
$ java -XX:AbortVMOnException=java.lang.StackOverflowError Main
The crash dump hs_err_pid.log contains the detailed stack trace where we can find interpreted frames at the bottom, C1 frames in the middle and lastly C2 frames on the top.
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
J 164 C2 Main.f()V (12 bytes) # 0x00007f21251a5958 [0x00007f21251a5900+0x0000000000000058]
J 164 C2 Main.f()V (12 bytes) # 0x00007f21251a5920 [0x00007f21251a5900+0x0000000000000020]
// ... repeated 19787 times ...
J 164 C2 Main.f()V (12 bytes) # 0x00007f21251a5920 [0x00007f21251a5900+0x0000000000000020]
J 163 C1 Main.f()V (12 bytes) # 0x00007f211dca50ec [0x00007f211dca5040+0x00000000000000ac]
J 163 C1 Main.f()V (12 bytes) # 0x00007f211dca50ec [0x00007f211dca5040+0x00000000000000ac]
// ... repeated 1866 times ...
J 163 C1 Main.f()V (12 bytes) # 0x00007f211dca50ec [0x00007f211dca5040+0x00000000000000ac]
j Main.f()V+8
j Main.f()V+8
// ... repeated 1839 times ...
j Main.f()V+8
j Main.main([Ljava/lang/String;)V+0
v ~StubRoutines::call_stub
First of all, the following has not been researched. I have not "deep dived" the OpenJDK source code to validate any of the following, and I don't have access to any inside knowledge.
I tried to validate your results by running your test on my machine:
$ java -version
openjdk version "1.8.0_71"
OpenJDK Runtime Environment (build 1.8.0_71-b15)
OpenJDK 64-Bit Server VM (build 25.71-b15, mixed mode)
I get the "count" varying over a range of ~250. (Not as much as you are seeing)
First some background. A thread stack in a typical Java implementation is a contiguous region of memory that is allocated before the thread is started, and that is never grown or moved. A stack overflow happens when the JVM tries to create a stack frame to make a method call, and the frame goes beyond the limits of the memory region. The test could be done by testing the SP explicitly, but my understanding is that it is normally implemented using a clever trick with the memory page settings.
When a stack region is allocated, the JVM makes a syscall to tell the OS to mark a "red zone" page at the end of the stack region read-only or non-accessible. When a thread makes a call that overflows the stack, it accesses memory in the "red zone" which triggers a memory fault. The OS tells the JVM via a "signal", and the JVM's signal handler maps it to a StackOverflowError that is "thrown" on the thread's stack.
So here are a couple of possible explanations for the variability:
The granularity of hardware-based memory protection is the page boundary. So if the thread stack has been allocated using malloc, the start of the region is not going to be page aligned. Therefore the distance from the start of the stack frame to the first word of the "red zone" (which >is< page aligned) is going to be variable.
The "main" stack is potentially special, because that region may be used while the JVM is bootstrapping. That might lead to some "stuff" being left on the stack from before main was called. (This is not convincing ... and I'm not convinced.)
Having said this, the "large" variability that you are seeing is baffling. Page sizes are too small to explain a difference of ~7000 in the counts.
UPDATE
When JIT is disabled (-Djava.compiler=NONE) I always get the same number (11907).
Interesting. Among other things, that could cause stack limit checking to be done differently.
This makes sense as JIT optimizations are probably affecting the size of stack frames and the work done by JIT definitely has to vary between the executions.
Plausible. The size of the stackframe could well be different after the f() method has been JIT compiled. Assuming f() was JIT compiled at some point you stack will have a mixture of "old" and "new" frames. If the JIT compilation occurred at different points, then the ratio will be different ... and hence the count will be different when you hit the limit.
Nevertheless, I think it would be beneficial if this theory is confirmed with references to some documentation about the topic and/or concrete examples of work done by JIT in this specific example that leads to frame size changes.
Little chance of that, I'm afraid ... unless you are prepared to PAY someone to do a few days research for you.
1) No such (public) reference documentation exists, AFAIK. At least, I've never been able to find a definitive source for this kind of thing ... apart from deep diving the source code.
2) Looking at the JIT compiled code tells you nothing of how the bytecode interpreter handled things before the code was JIT compiled. So you won't be able to see if the frame size has changed.
The exact functioning of Java stack undocumented, but it totally depends on the memory allocated to that thread.
Just try using the Thread constructor with stacksize and see if it gets constant. I have not tried it it, so please share the results.
I know this question has been answered before for Eclipse but can someone tell me how to increase heap space of my JCreator for a program in a bit more detailed manner (I am a beginner to Java programming).
Note: using -Xms248m -Xmx3072m in cmd.exe did not work
I had written
java -Xms256m -Xmx3072m MyClassName
The error occurred when i was making a large array to make a prime number seive up to a billion numbers.
I have 4GB of ram.
public class MyClassName {
public static void main(String[] args) {
int a[] = new int[1000000000];
}
}
When i run the below program i got the exception when for loop begins its execution at i=1031521. How to over come memory usage of this type?
class wwww
{
public static void main(String args[])
{
String abc[]=new String[4194304];
String wwf="";
int s_count=524286;
for(int i=0;i<4194304;i++)
{
System.out.println("----------enter--------"+i);
abc[i]=""+i;
System.out.println("----------exit--------"+i);
}
}
}
The exception is:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2882)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.
java:100)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:390
)
at java.lang.StringBuilder.append(StringBuilder.java:119)
at wwww.main(wwww.java:12)
This is because your your uses up all the heap space allocated to your jvm.
You can use argument while running the program to specify the heap size that you would like to allocate.
This is an example:
java -Xmx256m MyClass
Here a maximum of 256 MB of heap space will be allocated
How to over come memory usage of this type?
Don't perform memory usage of this type. You are creating 4194304 strings, of the general form ""+i. You don't need 4194304 strings of that form all at once. You only need one of them at a time, if any, and you can create it every time you need it.
You could either:
Increase the heap size that you give to your program. This is done via the -Xmx command-line argument to java.
Re-engineer the program to use less memory. Do you really need to keep all those strings in memory at once?