2015-07-07 14 views
26

'u engeller For döngüsünü kaldırdığımda bir OutOfMemoryError alır. Döngü için kullandığımda hata alamıyorum. Bu davranışı anlamada bana yardımcı olan var mı?Ekleme Döngüsü için OutOfMemoryError

public class JavaMemoryPuzzlePolite { 
    private final int dataSize = (int) (Runtime.getRuntime().maxMemory() * 0.6); 

    public void f() { 
     { 
      System.out.println(dataSize); 
      byte[] data = new byte[dataSize]; 
     } 
     for (int i = 0; i < 1; i++) { 
      System.out.println("Please be so kind and release memory"); 
     } 
     System.out.println(dataSize); 
     byte[] data2 = new byte[dataSize]; 
    } 

    public static void main(String[] args) { 
     JavaMemoryPuzzlePolite jmp = new JavaMemoryPuzzlePolite(); 
     jmp.f(); 
    } 
} 
+0

Ayrıca bkz. Http://stackoverflow.com/a/938080/545127 – Raedwald

cevap

28

f() yöntem yorumlanır çerçevede yürütülür. Yorumlanan çerçeveler, JIT ile derlenmiş çerçevelerden farklı davranır.

1. Allocate dataSize bytes of memory 
2. Store it into variable slot #1 
3. Allocate dataSize bytes of memory 
4. Store it into variable slot #1 

Yani yaşlı byte[] dizi hala değişken # 1'de bulunduğu gibi adım # 3 OutOfMemoryError var: o döngü olmadan pseudocode nasıl göründüğü burada. Ancak (aslında bir i değişkeni ekleme) döngü ekleyerek şey farklı kılan: Burada

1. Allocate dataSize bytes of memory 
2. Store it into variable slot #1 
3. Store 0 to slot #1 (thus byte[] array is now eligible for GC) 
4. Do the for loop 
5. Allocate dataSize bytes of memory 
6. Store it into variable slot #2 

adımda 5. yeni dizi tahsis zaman, ilk dizi zaten çöp toplanabilir.

JIT derleyicisinin daha akıllı davranabileceğini ve ilk diziyi, kullanılmayan hale geldikçe değişkenden çıkartabileceğini unutmayın (özellikle bu durumda, hiç ayırmayacaktır). Ayrıca, özel durumunuzda sonuçların java derleyicisine bağlı olduğunu unutmayın. ECJ (Eclipse derleyicisi), ilk diziyi, kullanılmadığı sürece değişkene depolamayacak kadar akıllıdır. Böylece, döngü olmadan bile ECJ derlenmiş sınıfta OutOfMemoryError almazsınız.

Daha fazla ayrıntı için javap yardımcı programı tarafından sağlanan bayt kodu demontaj çıkışına bakabilirsiniz ve değişken yuvaların nasıl yeniden kullanıldığını görebilirsiniz.

+0

Lütfen adım 3'ü biraz daha açıklayabilir misiniz? '3. 0'ı yuva # 1'e saklayın (böylece bayt [] dizisi artık GC için uygundur) ' – asgs

+3

@asgs, her yerel değişkenin javac derleyici tarafından atanmış olduğu bir yuvasına sahiptir. 'Data' 1 numaralı yuvaya atanır. Sonra blok biter, böylece slot yeniden kullanılabilir ve bir sonraki değişken de # 1 yuvasına sahip olacaktır. Döngü için bir sonraki değişken 'i' dir. Böylece, int i = 0 ', cevabımdaki "0 numaralı yuvaya # 1" olan "iconst_0/istore_1" öğesine çevrilir. Tercüman aslında yeni bir değişken olup olmadığı umurumda değil, sadece önceki değeri değiştirir, bu yüzden ilgisiz hale gelir. –

+0

@TagirValeev mükemmel, teşekkürler! "Iconst_0/istore_1", "Mağaza 1'den yuva # 1'e" değil, "1 numaralı yuvaya # 0" anlamına gelmez. – asgs

İlgili konular