Bir Java ilkelleri dizisi yığın veya yığın halinde mi depolanır?


85

Bunun gibi bir dizi bildirimim var:

int a[];

İşte abir ilkel inttip dizisi . Bu dizi nerede saklanıyor? Yığın mı yoksa yığın mı depolanıyor? Bu intilkel bir türdür , tüm ilkel türler yığın üzerinde depolanmaz.


38
Bu bir dizi değil. Bir diziye referanstır. Başvurunun kendisi, bir sınıfın veya nesnenin üyesiyse öbek üzerinde veya bir yöntemdeki yerel bir değişkense yığında saklanabilir. Ve ilkel türler, bir sınıfın veya nesnenin üyeleriyse, yığın üzerinde depolanabilir.
amcaO

Yanıtlar:


145

Gurukulki'nin dediği gibi, yığında saklanır. Bununla birlikte, gönderiniz muhtemelen iyi niyetli bir kişinin "ilkellerin her zaman yığında yaşadığı" mitini yaymasından dolayı bir yanlış anlaşılmayı önerdi. Bu doğru değil. Yerel değişkenlerin değerleri yığın üzerindedir, ancak tüm ilkel değişkenler yerel değildir ...

Örneğin, şunu düşünün:

public class Foo
{
    int value;
}
...

public void someOtherMethod()
{
    Foo f = new Foo();
    ...
}

Şimdi, nerede f.valueyaşıyor? Efsane onun yığında olduğunu öne sürüyordu - ama aslında yeni Foonesnenin bir parçası ve yığın 1'de yaşıyor . ( fKendisinin değerinin bir referans olduğunu ve yığında yaşadığını unutmayın.)

Oradan dizilere geçmek kolay bir adımdır. Bir diziyi yalnızca bir çok değişken olarak düşünebilirsiniz - bu new int[3], bu formda bir sınıfa sahip olmak gibi bir şeydir:

public class ArrayInt3
{
    public readonly int length = 3;
    public int value0;
    public int value1;
    public int value2;
}

1 Aslında, bundan daha karmaşık. Yığın / yığın ayrımı çoğunlukla bir uygulama ayrıntısıdır - bazı JVM'lerin, muhtemelen deneysel olanların, bir nesnenin bir yöntemden asla "kaçmadığını" anlayabileceğine ve tüm nesneyi yığına tahsis edebileceğine inanıyorum. Ancak, umursamayı seçerseniz, kavramsal olarak yığında.


1
Java'daki "kaçış analizi " hakkında: blog.juma.me.uk/2008/12/17/objects-with-no-allocation-overhead JDK 6 Güncelleme 14'ün erken erişim sürümünden beri mevcut olduğunu ve JDK 6 Güncelleme 23'ten beri varsayılan olarak etkindir.
Guido

dizi public static final ise herhangi bir şey değiştirir mi? O halde sabit havuzun bir parçası olması gerekmez mi?
Malachiasz

@Malachiasz: Hayır. Bir dizi asla sabit değildir.
Jon Skeet

@JonSkeet: Bildiğim Java kitaplığının tüm sürümlerinde, her Stringbiri bir char[]. Birebir dizgelerin genel sabit havuzda saklandığına inanıyorum; GC optimizasyonu için, bu, arka dizilerin benzer şekilde depolanması gerektiği anlamına gelir (aksi takdirde, sabit havuzun, aksi takdirde arka dizinin toplama için uygun olacağı herhangi bir GC döngüsü sırasında taranması gerekir).
supercat

@supercat: Evet, bu mantıklı. Ancak, kendinizi ilan ettiğiniz herhangi bir dizi, asla sabit havuzun bir parçası olmaz.
Jon Skeet

37

Yığın üzerinde depolanacak

çünkü dizi java'da bir nesnedir.

DÜZENLEME : eğer varsa

int [] testScores; 
testScores = new int[4];

Bu kodun derleyiciye şunu söylediğini düşünün, "Dört girişi tutacak bir dizi nesnesi oluşturun ve bunu adlandırılmış referans değişkenine atayın testScores. Ayrıca devam edin ve her bir intöğeyi sıfıra ayarlayın. Teşekkürler."


3
Ve testScores adlı referans değişkeni (öbek üzerindeki diziyi işaret eden) yığın üzerinde olacaktır.
Zaki

11
-gDerleyiciye seçeneği sağlarsanız kod yalnızca "Teşekkürler" der . Aksi takdirde optimize edilecektir.
mob

1
@mob Bunun tek kod olduğunu varsayıyorsunuz. Bu iki satırın diziyi kullanan daha büyük bir programın parçası olduğunu varsaymak muhtemelen daha iyidir.
Code-Apprentice

22

Kendi içinde ilkel olmayan bir ilkel türler dizisidir. İyi bir pratik kural, yeni anahtar kelime dahil edildiğinde sonucun yığın üzerinde olacağıdır.


19

Bu konuda yaptığım birkaç testi paylaşmak istedim.

10 milyon boyutunda dizi

public static void main(String[] args) {
    memInfo();
    double a[] = new double[10000000];
    memInfo();
}

Çıktı:

------------------------
max mem = 130.0 MB
total mem = 85.0 MB
free mem = 83.6 MB
used mem = 1.4 MB
------------------------
------------------------
max mem = 130.0 MB
total mem = 130.0 MB
free mem = 48.9 MB
used mem = 81.1 MB
------------------------

Gördüğünüz gibi kullanılan yığın boyutu, 10m * sizeof (double) olan ~ 80 MB artırıldı.

Ancak double yerine Double kullanırsak

public static void main(String[] args) {
    memInfo();
    Double a[] = new Double[10000000];
    memInfo();
}

Çıktı 40MB gösterecektir. Sadece Çift referanslarımız var, bunlar başlatılmamış.

Double ile doldurmak

public static void main(String[] args) {
    memInfo();
    Double a[] = new Double[10000000];      
    Double qq = 3.1d;
    for (int i = 0; i < a.length; i++) {
        a[i] = qq;
    }
    memInfo();
}

Hala 40MB. Çünkü hepsi aynı Double nesnesine işaret ediyor.

Bunun yerine double ile başlatılıyor

public static void main(String[] args) {
    memInfo();
    Double a[] = new Double[10000000];
    Double qq = 3.1d;
    for (int i = 0; i < a.length; i++) {
        a[i] = qq.doubleValue();
    }
    memInfo();
}

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

Hat

a[i] = qq.doubleValue();

eşdeğerdir

a[i] = Double.valueOf(qq.doubleValue());

eşdeğer olan

a[i] = new Double(qq.doubleValue());

Her seferinde yeni Double nesneler yarattığımız için, yığını uçuruyoruz. Bu, Double sınıfı içindeki değerlerin yığın içinde depolandığını gösterir.


1
MemInfo () pls kod detayını yapıştırabilir misiniz? :)
hedleyyan

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.