I'm doing some tests on Java heap with IntelliJ and I get this error:
java.lang.OutOfMemoryError: GC overhead limit exceeded.
I know this happens when GC takes too much time, but I can not understand why does GC happens so frequently and takes so much time.
Design:
In the main thread, I create new objects repeatly, then put them in a map. To prevent these objects collected, I will print these objects after putting all of them into the map.
In the monitor thread, I print current free heap size every time I create a new object.
Runtime heap size configuration:
-Xms5m -Xmx5m
Test code:
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class Example {
public static ReentrantLock lock = new ReentrantLock(true);
public static Condition writeCondition = lock.newCondition();
public static Condition monitorCondition = lock.newCondition();
public static void main(String[] args) throws Exception {
new Thread(new Monitor(lock, writeCondition, monitorCondition)).start(); // start a monitor thread
Map<Integer, Object> map = new HashMap<>();
for (int count = 0; count < 10000000; count++) {
lock.lock();
try {
// every time create a new Object, I will use monitor thread print current free heap size
monitorCondition.signal();
map.put(count, new Object());
writeCondition.await();
} finally {
lock.unlock();
}
}
for (Map.Entry entry : map.entrySet()) {
// keep reference to these Objects, so they will not be garbage collected.
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
}
}
class Monitor implements Runnable {
ReentrantLock lock;
Condition writeCondition;
Condition monitorCondition;
public Monitor(ReentrantLock lock, Condition writeCondition, Condition monitorCondition) {
this.lock = lock;
this.writeCondition = writeCondition;
this.monitorCondition = monitorCondition;
}
@Override
public void run() {
int count = 0;
while (true) {
lock.lock();
try {
writeCondition.signal();
long heapFreeSize = Runtime.getRuntime().freeMemory();
System.out.println(count + " times run monitor : ");
System.out.println("heapFreesize : " + heapFreeSize);
System.out.println();
count++;
monitorCondition.await();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
Result:
60005 times run monitor :
heapFreesize:603896
Exception in thread "Thread-0" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.nio.CharBuffer.wrap(CharBuffer.java:373)
at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:265)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
at java.io.PrintStream.newLine(PrintStream.java:545)
at java.io.PrintStream.println(PrintStream.java:696)
at hello.Monitor.run(Example.java:58)
at java.lang.Thread.run(Thread.java:748)