簡體   English   中英

如何重現Java OutOfMemoryError - 超出了GC開銷限制

[英]How to reproduce Java OutOfMemoryError - GC overhead limit exceeded

我的方法是創建十萬個本地集合並用隨機字符串填充它們,如下所示:

    SecureRandom random = new SecureRandom();
    for(int i = 0 ; i < 100000 ; i++){
        HashMap<String, String> map = new HashMap<String, String>();
        for(int j = 0 ; j < 30 ; j++){
            map.put(new BigInteger(130, random).toString(32), new BigInteger(130, random).toString(32));
        }
    }

我也提供了-XX:+ UseGCOverheadLimit jvm參數,但無法獲取錯誤。 是否有任何簡單可靠的方法/黑客來獲取此錯誤?

既然你沒有接受任何答案,我會假設他們都沒有為你工作。 這是一個會。 但首先,審查觸發此錯誤的條件

如果在垃圾收集中花費了太多時間,則並行收集器將拋出OutOfMemoryError:如果超過98%的總時間用於垃圾收集並且回收的堆少於2%

因此,您必須消耗幾乎所有的堆,保持分配,然后分配大量垃圾。 將大量內容放入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)

現在我的問題是你:為什么你想在世界上做這個?

這個:

HashMap<String, String> map = new HashMap<String, String>();

循環中作用域,並且在循環迭代時沒有創建對映射的外部(長期)引用。 因此,每個循環迭代結束時,每個映射都有資格進行垃圾收集。

您需要在循環創建一個對象集合,並使用循環來填充該集合。

我認為這應該可以解決問題......如果你跑的時間足夠長:

HashMap<Long, String> map = new HashMap<Long, String>();
for (long i = 0; true; i++) {
    for (int j = 0; j < 100; j++) {
        String s = "" + j;
        map.put(i, s);
    }
}

我正在做的是慢慢增加非垃圾量,同時創造大量垃圾。 如果運行此操作直到非垃圾填滿幾乎所有堆,則GC將達到垃圾收集所花費的時間百分比超過閾值的點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM