Hata java.lang.OutOfMemoryError: GC ek yük sınırı aşıldı

JUnit testlerimi çalıştırdığımda bu hata mesajını alıyorum:

java.lang.OutOfMemoryError: GC overhead limit exceeded

OutOfMemoryError`ın ne olduğunu biliyorum, ancak GC genel gider sınırı ne anlama geliyor? Bunu nasıl çözebilirim?

Çözüm

Bu mesaj, çöp toplayıcının bazı nedenlerden dolayı aşırı miktarda zaman aldığı (varsayılan olarak sürecin tüm CPU zamanının %98'i) ve her çalıştırmada çok az bellek kurtardığı (varsayılan olarak yığının %2'si) anlamına gelir.

Bu, programınızın herhangi bir ilerleme kaydetmeyi durdurduğu ve her zaman yalnızca çöp toplama işlemini yürütmekle meşgul olduğu anlamına gelir.

Uygulamanızın hiçbir şey yapmadan CPU zamanını tüketmesini önlemek için JVM bu Hatayı atar, böylece sorunu teşhis etme şansınız olur.

Bunun gerçekleştiğini gördüğüm nadir durumlar, bazı kodların zaten çok kısıtlı belleğe sahip bir ortamda tonlarca geçici nesne ve tonlarca zayıf referanslı nesne oluşturduğu durumlardı.

Ayrıntılar için bu makaleye göz atın (özellikle bu bölüm).

Yorumlar (14)

GC, çok az getiri için çöp toplamada çok fazla zaman harcandığında bu istisnayı atar, örneğin CPU zamanının %98'i GC'ye harcanır ve heap'in %2'sinden daha azı kurtarılır.

Bu özellik, yığın çok küçük olduğu için uygulamaların çok az ilerleme kaydederken veya hiç ilerleme kaydedemezken uzun süre çalışmasını önlemek için tasarlanmıştır.

Bunu komut satırı seçeneği ile kapatabilirsiniz -XX:-UseGCOverheadLimit

Daha fazla bilgi burada

DÜZENLEME: Görünüşe göre birisi benden daha hızlı yazabiliyor :)

Yorumlar (6)

Genellikle koddur. İşte basit bir örnek:

import java.util.*;

public class GarbageCollector {

    public static void main(String... args) {

        System.out.printf("Testing...%n");
        List list = new ArrayList();
        for (int outer = 0; outer < 10000; outer++) {

            // list = new ArrayList(10000); // BAD
            // list = new ArrayList(); // WORSE
            list.clear(); // BETTER

            for (int inner = 0; inner < 10000; inner++) {
                list.add(Math.random());
            }

            if (outer % 1000 == 0) {
                System.out.printf("Outer loop at %d%n", outer);
            }

        }
        System.out.printf("Done.%n");
    }
}

Windows7 32 bit üzerinde java 1.6.0_24-b07 kullanılıyor.

java -Xloggc:gc.log GarbageCollector

Sonra gc.log dosyasına bakın

  • BAD yöntemi kullanılarak 444 kez tetiklendi
  • WORSE yöntemi kullanılarak 666 kez tetiklendi
  • BETTER yöntemi kullanılarak 354 kez tetiklendi

Kabul etmek gerekir ki, bu en iyi test ya da en iyi tasarım değildir, ancak böyle bir döngüyü uygulamaktan başka seçeneğinizin olmadığı bir durumla karşı karşıya kaldığınızda ya da kötü davranan mevcut kodla uğraşırken, yeni nesneler oluşturmak yerine nesneleri yeniden kullanmayı seçmek çöp toplayıcının yolunuza çıkma sayısını azaltabilir...

Yorumlar (1)