由于您尚未接受任何答案,我将假设它们都对您无效。这里有一个有效的解决方法。但首先,请回顾一下
触发此错误的条件:
如果垃圾收集所花费的时间太长,即垃圾收集所占用的总时间超过98%且恢复的堆内存不到2%,则并行收集器会抛出OutOfMemoryError
因此,您必须几乎使用完整个堆,保持其分配状态,然后分配大量垃圾。向 Map
中添加大量内容无法实现此目的。
public static void main(String[] argv)
throws Exception
{
List<Object> fixedData = consumeAvailableMemory();
while (true)
{
Object data = new byte[64 * 1024 - 1];
}
}
private static List<Object> consumeAvailableMemory()
throws Exception
{
LinkedList<Object> holder = new LinkedList<Object>();
while (true)
{
try
{
holder.add(new byte[128 * 1024]);
}
catch (OutOfMemoryError ex)
{
holder.removeLast();
return holder;
}
}
}
consumeAvailableMemory()
方法会使用相对较小的内存块填充堆。"相对较小" 很重要,因为JVM会直接将 "大" 对象(根据我的经验,512k字节)放入旧生代,使年轻代保持空闲。
当我使用了大部分堆后,我只需分配和丢弃。在这个阶段中,较小的块大小很重要:我知道我至少有足够的内存进行一次分配,但可能不超过两次。这将保持GC处于活动状态。
运行此操作会在不到一秒钟内产生所需的错误。
> java -Xms1024m -Xmx1024m GCOverheadTrigger
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at GCOverheadTrigger.main(GCOverheadTrigger.java:12)
为了完整起见,这是我正在使用的JVM:
> java -version
java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.45-b01, mixed mode)
现在我有一个问题要问你:为什么世界上你会想要这样做呢?
for
循环之外声明的集合中,并在第一个for
循环之前添加while(true)
。 - Luiggi Mendoza