2010-01-20 20 views
70

mam deklarację tablicy tak:Czy tablica Java prymitywów jest przechowywana w stosie lub sterty?

int a[]; 

Tutaj a jest tablicą prymitywnego int typu. Gdzie jest przechowywana ta tablica? Czy jest on przechowywany na stercie lub stosie? Jest to typ pierwotny int, wszystkie typy pierwotne nie są przechowywane na stercie.

+35

To nie jest tablica. Jest to odniesienie do tablicy. Samo odniesienie może być przechowywane na stercie, jeśli jest członkiem klasy lub obiektu, lub na stosie, jeśli jest to zmienna lokalna w metodzie. Typy pierwotne mogą być przechowywane na stercie, jeśli są członkami klasy lub obiektu. – UncleO

Odpowiedz

32

to zostanie zapisany na sterty

ponieważ tablica jest obiekt w Java.

EDIT. Jeśli masz

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

myśleć o tym kodzie, co mówią do kompilatora „Utwórz obiekt tablicę, która będzie trzymać cztery ints i przypisać ją do zmiennej referencyjnej o nazwie testScores także , ustaw każdy element int na zero. Dzięki. "

+2

Zmienna odniesienia o nazwie testScores (wskazująca na tablicę na stercie) zostanie umieszczona na stosie. – Zaki

+8

Kod mówi "Dzięki", jeśli podasz opcję '-g' dla kompilatora. W przeciwnym razie zostanie zoptymalizowany. – mob

+0

@mob Zakłada się, że jest to jedyny kod. Prawdopodobnie lepiej jest założyć, że te dwie linie są częścią większego programu, który faktycznie używa tablicy. –

18

jest szereg typów pierwotnych, które samo w sobie nie jest prymitywny. Dobra zasada jest taka, że ​​gdy nowe słowo kluczowe jest zaangażowane, wynik będzie na kupie.

132

Jak powiedział gurukulki, jest on przechowywany na stercie. Jednak twój post zasugerował nieporozumienie prawdopodobnie ze względu na osobę o dobrej intencji propagującą mit, że "prymitywy zawsze żyją na stosie". To nieprawda. Zmienne lokalne mają swoje wartości na stosie, ale nie wszystkie zmienne lokalne są prymitywne ...

Na przykład, rozważ to:

public class Foo 
{ 
    int value; 
} 
... 

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

Teraz, skąd f.value żyć? Mit sugerowałby, że jest na stosie - ale w rzeczywistości jest to część nowego obiektu Foo i żyje na sterty . (Zauważ, że wartość f sama w sobie jest odniesieniem i żyje na stosie.)

Stamtąd łatwo jest posortować. Można myśleć o tablicę jak po prostu dużo zmiennych - tak new int[3] jest trochę jak o klasie tego formularza:

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

W rzeczywistości jest to bardziej skomplikowane niż to. Rozróżnienie stosu/sterty jest głównie szczegółem implementacji - uważam, że niektóre maszyny JVM, prawdopodobnie eksperymentalne, mogą stwierdzić, kiedy obiekt nigdy "nie" ucieka z metody i może przydzielić cały obiekt na stosie. Jednak na kupce jest pojęcie konceptualnie, jeśli chcesz się tym przejmować.

+1

O "analizie ucieczki" w Javie: http://blog.juma.me.uk/2008/12/17/objects-with-no-allocation-overhead/ Mówi, że jest obecna od wczesnego dostępu wydanie JDK 6 Update 14, i włączone domyślnie od JDK 6 Update 23. –

+0

czy zmienia wszystko, jeśli tablica jest publicznym statycznym końcowym? Czy nie powinien wtedy być częścią stałej puli? – Malachiasz

+0

@Malachiasz: Nie. Tablica nigdy nie jest stała. –

14

Po prostu chciałem podzielić się kilkoma testami, które prowadziłem na ten temat.

Array wielkości 10 milionów

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

wyjściowa:

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

Jak widać używane wielkość sterty jest zwiększona o ~ 80 MB, który jest 10m * sizeof (double).

Ale jeśli mamy użyć dwukrotnie zamiast podwójnego

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

Output pokaże 40MB. Mamy tylko podwójne referencje, nie są one inicjowane.

Wypełnianie go z podwójnym

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(); 
} 

Still 40MB. Ponieważ wszystkie wskazują na ten sam podwójny obiekt.

Inicjowanie podwójne zamiast

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 

Linia

a[i] = qq.doubleValue(); 

odpowiada

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

co jest równoważne

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

Ponieważ za każdym razem tworzymy nowe Podwójne obiekty, wysadzamy stertę. To pokazuje, że wartości wewnątrz klasy Double są przechowywane w stercie.

Powiązane problemy