【发布时间】:2018-02-16 09:27:00
【问题描述】:
我正在使用 IntelliJ 对 Java 堆进行一些测试,但出现此错误:
java.lang.OutOfMemoryError: GC overhead limit exceeded.
我知道当 GC 花费太多时间时会发生这种情况,但我不明白为什么 GC 发生如此频繁且花费如此多的时间。
设计:
在主线程中,我重复创建新对象,然后将它们放入地图中。为了防止这些对象被收集,我将这些对象全部放入地图后打印出来。
在监控线程中,每次创建新对象时都会打印当前空闲堆大小。
运行时堆大小配置:
-Xms5m -Xmx5m
测试代码:
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();
}
}
}
}
结果:
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)
【问题讨论】:
-
在这段代码中,您试图将 1000 万个对象(通常每个 8 字节)放入一个 5Mb 的堆中(甚至不计算运行时和您使用的其他元素的开销)。那不会起作用。
-
@gpeche 是的,事实上我期待
OutOfMemoryError。但我不明白为什么 GC 需要这么多时间。因为我创建的对象不应该被垃圾回收。
标签: java garbage-collection jvm