99 votes

Un tableau de primitives Java est-il stocké dans la pile ou le tas ?

J'ai une déclaration de tableau comme ceci :

int a[];

Ici a est un tableau de primitives int type. Où est stocké ce tableau ? Est-il stocké sur le tas ou la pile ? C'est un type primaire int tous les types primitifs ne sont pas stockés sur le tas.

42 votes

Ce n'est pas un tableau. C'est une référence à un tableau. La référence elle-même peut être stockée sur le tas si elle est membre d'une classe ou d'un objet, ou sur la pile si elle est une variable locale dans une méthode. Et les types primitifs peuvent être stockés sur le tas s'ils sont membres d'une classe ou d'un objet.

164voto

Jon Skeet Points 692016

Comme l'a dit Gurukulki, c'est stocké dans le tas. Cependant, votre message suggère un malentendu probablement dû à une personne bien intentionnée qui propage le mythe selon lequel "les primitives vivent toujours sur la pile". Ce n'est pas vrai. Variables locales ont leurs valeurs sur la pile, mais toutes les variables primitives ne sont pas locales...

Par exemple, considérez ceci :

public class Foo
{
    int value;
}
...

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

Maintenant, où est-ce que f.value en vie ? Le mythe voudrait que ce soit sur la pile - mais en fait, cela fait partie du nouveau système de gestion de l'énergie. Foo et vit sur le tas 1 . (Notez que la valeur de f est elle-même une référence, et vit sur la pile).

À partir de là, il est facile de passer aux tableaux. Vous pouvez considérer qu'un tableau est simplement un ensemble de variables, comme par exemple new int[3] c'est un peu comme avoir une classe de cette forme :

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

1 En fait, c'est plus compliqué que ça. La distinction pile/cheap est principalement un détail d'implémentation - je crois que certaines JVM, peut-être expérimentales, peuvent dire quand un objet ne s'échappe jamais d'une méthode, et peuvent allouer l'objet entier sur la pile. Cependant, c'est conceptuellement sur le tas, si vous choisissez de vous en soucier.

1 votes

À propos de l'"analyse d'échappement" en Java : blog.juma.me.uk/2008/12/17/objects-with-no-allocation-overhead Il est indiqué qu'il est présent depuis la version d'accès anticipé du JDK 6 Update 14, et activé par défaut depuis le JDK 6 Update 23.

0 votes

Est-ce que cela change quelque chose si le tableau est public static final ? Ne devrait-il pas alors faire partie du pool de constantes ?

0 votes

@Malachiasz : Nope. Un tableau n'est jamais une constante.

43voto

GuruKulki Points 7974

Il sera stocké sur le amas

parce que le tableau est un objet en java.

EDITAR : si vous avez

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

Imaginez que ce code dise au compilateur : "Créez un objet de type tableau qui contiendra quatre ints, et affectez-le à la variable de référence nommée testScores . Aussi, allez-y et définissez chaque int à zéro. Merci."

5 votes

Et la variable de référence nommée testScores (pointant vers le tableau sur le tas) sera sur la pile.

12 votes

Le code ne dit "Merci" que si vous fournissez l'élément -g au compilateur. Sinon, il sera optimisé.

1 votes

@mob Vous supposez que c'est le seul code. Il est probablement préférable de supposer que ces deux lignes font partie d'un programme plus large qui utilise réellement le tableau.

27voto

C'est un tableau de types primitifs qui, en soi, n'est pas primitif. Une bonne règle de base est que lorsque le mot-clé new est impliqué, le résultat sera sur le tas.

23voto

acheron55 Points 713

Je voulais juste partager quelques tests que j'ai effectués sur ce sujet.

Tableau de taille 10 millions

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

Sortie :

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

Comme vous le voyez, la taille du tas utilisé est augmentée de ~80 MB, soit 10m * sizeof(double).

Mais si nous avons utilisé Double au lieu de double

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

La sortie montrera 40MB. Nous avons seulement des références doubles, elles ne sont pas initialisées.

Remplir avec Double

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

Toujours 40MB. Parce qu'ils pointent tous vers le même objet Double.

Initialisation avec un double à la place

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

Ligne

a[i] = qq.doubleValue();

est équivalent à

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

ce qui est équivalent à

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

Comme nous créons de nouveaux objets Double à chaque fois, nous faisons exploser le tas. Cela montre que les valeurs de la classe Double sont stockées dans le tas.

4 votes

Pourriez-vous coller le détail du code de memInfo() svp ? :)

3voto

Nikola Gedelovski Points 425

Dans le langage de programmation Java, les tableaux sont des objets, ils sont créés dynamiquement et peuvent être affectés à des variables de type Object.

http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X