17

私のアプローチは、10 万個のローカル コレクションを作成し、次のようなランダムな文字列を入力することでした。

    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 パラメータも指定しましたが、エラーが発生しません。このエラーを取得するための簡単で信頼できる方法/ハックはありますか?

4

3 に答える 3

13

あなたは何の回答も受け入れていないので、私はそれらのどれもあなたのために働いていないと仮定します. これがその1つです。ただし、最初に、このエラーをトリガーする条件を確認します。

ガベージ コレクションに時間がかかりすぎる場合、並列コレクターは 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 バイト) を Tenured 世代に直接配置し、若い世代を空のままにするため、「比較的小さい」ことが重要です。

ヒープの大部分を消費したら、割り当てて破棄します。このフェーズでは、ブロック サイズが小さいことが重要です。少なくとも 1 つの割り当てに十分なメモリがあることはわかっていますが、おそらく 2 つを超えることはありません。これにより、GC がアクティブなままになります。

これを実行すると、1 秒以内に目的のエラーが生成されます。

> 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)

そして今、あなたへの私の質問: なぜあなたはこれをしたいのですか?

于 2013-06-21T12:25:13.843 に答える
2

これ:

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

ループ内でスコープが設定され、ループの反復時に作成されるマップへの外部 (長期) 参照はありません。したがって、各マップは、各ループ反復の最後にガベージ コレクションの対象になります。

ループの外側でオブジェクトのコレクションを作成し、ループを使用してそのコレクションを作成する必要があります。

于 2013-06-14T16:11:12.913 に答える
0

これでうまくいくと思います...十分に長く実行すれば:

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 が到達します。

于 2013-06-14T16:23:33.687 に答える