Quelle est la consommation de mémoire D'un objet en Java?

est - ce que l'espace mémoire consommé par un objet avec 100 attributs est le même que celui de 100 objets, avec un attribut chacun?

quelle quantité de mémoire est attribuée à un objet?

De combien d'espace supplémentaire est utilisé lors de l'ajout d'un attribut?

188
demandé sur keparo 2008-11-03 11:24:48

12 réponses

Mindprod souligne que ce n'est pas une question simple à répondre:

une JVM est libre de stocker des données de n'importe quelle manière qu'elle veut à l'intérieur, grand ou petit endian, avec n'importe quelle quantité de rembourrage ou au-dessus, bien que les primitifs doivent se comporter comme s'ils avaient les tailles officielles.

Par exemple, le JVM ou le compilateur natif pourrait décider de stocker un boolean[] en morceaux de 64 bits comme un BitSet . Il n'a pas à vous dire, tant que le programme donne les mêmes réponses.

  • il peut affecter certains objets temporaires sur la pile.
  • il peut optimiser certaines variables ou la méthode appelle totalement hors de l'existence en les remplaçant par des constantes.
  • il peut modifier des méthodes ou des boucles, c'est-à-dire compiler deux versions d'une méthode, chacune optimisée pour une certaine situation, puis décider à l'avance l'un à l'appel.

alors, bien sûr, le matériel et L'OS ont des caches multicouches, sur la mémoire cache-puce, la mémoire cache SRAM, la mémoire cache DRAM, la mémoire vive RAM ordinaire et la mémoire de sauvegarde sur disque. Vos données peuvent être dupliquées à chaque niveau de cache. Toute cette complexité signifie que vous ne pouvez prédire que très grossièrement la consommation de RAM.

méthodes de mesure

Vous pouvez utiliser Instrumentation.getObjectSize() pour obtenir un estimation du stockage consommé par un objet.

pour visualiser le réel layout d'objet, empreinte au sol, et références, vous pouvez utiliser l'outil JOL (Java Object Layout) .

en-têtes D'objets et références D'objets

dans un JDK moderne de 64 bits, un objet a un en-tête de 12 octets, rembourré à un multiple de 8 octets, de sorte que la taille minimale de l'objet est de 16 octets. Pour 32-bit Jvm, la les frais généraux est de 8 octets, collier pour un multiple de 4 octets. (De Dmitry Spikhalskiy la réponse de , Jayen la réponse de , et JavaWorld .)

typiquement, les références sont 4 octets sur les plates-formes de 32 bits ou sur les plates-formes de 64 bits jusqu'à -Xmx32G ; et 8 octets au-dessus de 32 Go ( -Xmx32G ). (voir références d'objets comprimés .)

par conséquent, une MVC 64 bits nécessiterait généralement de 30 à 50% plus d'espace en tas. ( dois-je utiliser un 32 ou un 64 bits JVM? , 2012, JDK 1.7)

Boxed types, les tableaux et les chaînes de caractères

emballages Boxed ont overhead par rapport aux types primitifs (de JavaWorld ):

  • Integer : le résultat de 16 octets est un peu plus mauvais que prévu car une valeur int peut s'insérer dans seulement 4 octets supplémentaires. L'utilisation d'un Integer me coûte 300 pour cent de mémoire aérienne par rapport à quand je peux stocker la valeur comme un type primitif

  • Long : 16 bytes aussi: clairement, la taille réelle de l'objet sur le tas est sujette à un alignement de mémoire de bas niveau fait par une JVM particulière mise en œuvre pour un type de CPU particulier. Il ressemble à un Long est de 8 bytes D'objet au-dessus, plus 8 bytes de plus pour la valeur réelle longue. En revanche, Integer avait un trou de 4 octets inutilisé, probablement parce que le JVM I utilise des forces d'alignement de l'objet sur une limite de mots de 8 octets.

D'autres conteneurs sont coûteux aussi:

  • Tableaux multidimensionnels : il offre une autre surprise.

    Les développeurs emploient couramment des concepts comme int[dim1][dim2] dans le calcul numérique et scientifique.

    dans une instance de tableau int[dim1][dim2] , chaque tableau imbriqué int[dim2] est un Object à part entière. Chacun ajoute le tableau habituel de 16 octets au-dessus. Quand je n'ai pas besoin d'un tableau triangulaire ou déchiqueté, cela représente le ciel pur. L'impact se produit lorsque les dimensions du réseau grandement différer.

    par exemple, une instance int[128][2] prend 3 600 octets. Par rapport aux 1.040 octets qu'utilise une instance int[256] (qui a la même capacité), 3.600 octets représentent une overhead de 246%. Dans le cas extrême de byte[256][1] , le facteur de frais généraux est presque 19! Comparez cela à la situation C/C++ dans laquelle la même syntaxe n'ajoute pas de frais généraux de stockage.

  • String : la croissance de la mémoire d'un String suit la croissance de son réseau interne. Cependant, la classe String ajoute 24 octets supplémentaires de overhead.

    pour un String de taille 10 caractères ou moins, les frais généraux supplémentaires relatifs à la charge utile (2 octets pour chaque char plus 4 octets pour la longueur), varie de 100 à 400 pour cent.

alignement

exemple d'objet :

class X {                      // 8 bytes for reference to the class definition
   int a;                      // 4 bytes
   byte b;                     // 1 byte
   Integer c = new Integer();  // 4 bytes for a reference
}

une somme naïve suggérerait qu'une instance de X utiliserait 17 octets. Cependant, en raison de l'alignement (aussi appelé capitonnage), la JVM alloue la mémoire en multiples de 8 octets, donc au lieu de 17 octets elle attribuerait 24 octets.

158
répondu VonC 2017-05-23 12:26:31

chaque objet a un certain overhead pour les informations de type et de moniteur associées, ainsi que les champs eux-mêmes. Au - delà de cela, les champs peuvent être disposés assez bien que la JVM le juge approprié (je crois) - mais comme montré dans une autre réponse , au moins certains JVM emballeront assez étroitement. Considérez une classe comme celle-ci:

public class SingleByte
{
    private byte b;
}

vs

public class OneHundredBytes
{
    private byte b00, b01, ..., b99;
}

sur un JVM de 32 bits, je m'attendais à 100 les instances de SingleByte à prendre 1200 octets (8 octets de overhead + 4 octets pour le champ en raison du remplissage/alignement). Je m'attendais à ce qu'une instance de OneHundredBytes prenne 108 octets - le overhead, puis 100 octets, emballé. Il peut certainement varier par JVM bien qu'une implémentation puisse décider de ne pas empaqueter les champs dans OneHundredBytes , conduisant à ce qu'il prenne 408 bytes (= 8 bytes overhead + 4 * 100 aligned/padded bytes). Sur un JVM de 64 bits, le overhead peut aussi être plus grand (pas sûr).

EDIT: Voir le commentaire ci-dessous; apparemment HotSpot plaquettes de 8 limites d'octets au lieu de 32, de sorte que chaque instance de SingleByte 16 octets.

dans les deux cas, le" seul grand objet " sera au moins aussi efficace que plusieurs petits objets - pour des cas simples comme celui-ci.

26
répondu Jon Skeet 2017-05-23 12:10:46

cela dépend de l'architecture/jdk. Pour une architecture JDK et 64bit moderne, un objet a un en-tête de 12 octets et un rembourrage de 8 octets - donc la taille minimale de l'objet est de 16 octets. Vous pouvez utiliser un outil appelé Java Object Layout pour déterminer une taille et obtenir des détails sur la mise en page des objets et la structure interne de n'importe quelle entité ou deviner cette information par référence de classe. Exemple d'une sortie pour entier sur mon environnement:

Running 64-bit HotSpot VM.
Using compressed oop with 3-bit shift.
Using compressed klass with 3-bit shift.
Objects are 8 bytes aligned.
Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

java.lang.Integer object internals:
 OFFSET  SIZE  TYPE DESCRIPTION                    VALUE
      0    12       (object header)                N/A
     12     4   int Integer.value                  N/A
Instance size: 16 bytes (estimated, the sample instance is not available)
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

donc, pour entier, la taille de l'instance est de 16 octets, parce que 4 octets int compacté en place juste après l'en-tête et avant la limite de remplissage.

exemple de Code:

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.util.VMSupport;

public static void main(String[] args) {
    System.out.println(VMSupport.vmDetails());
    System.out.println(ClassLayout.parseClass(Integer.class).toPrintable());
}

si vous utilisez maven, pour obtenir JOL:

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.3.2</version>
</dependency>
21
répondu Dmitry Spikhalskiy 2018-07-11 17:04:53

Non, enregistrer un objet prend un peu de mémoire aussi. 100 objets avec 1 attribut prendra plus de mémoire.

5
répondu Mendelt 2008-11-03 08:26:17

est-ce que l'espace mémoire consommé par un objet avec 100 attributs est le même que celui de 100 objets, avec un attribut chacun?

Pas de.

quelle quantité de mémoire est attribuée à un objet?

  • La surcharge est de 8 octets sur 32 bits, 12 octets sur 64 bits, puis arrondis à un multiple de 4 octets (32 bits) ou 8 octets (64 bits).

Combien d'espace supplémentaire est utilisé lors de l'ajout d'un attribut?

  • Attributs de gamme de 1 octet (char/boolean) à 8 octets (long double), mais les références sont soit 4 octets 8 octets en fonction pas si c'est 32 bits ou 64 bits, mais plutôt de savoir si -Xmx est < 32 go ou >= 32 go: typique de la JVM 64 bits ont une optimisation appelée "-UseCompressedOops" qui compriment les références à 4 octets si le tas est en dessous de 32 Go.
5
répondu Jayen 2016-02-15 11:38:29

la mémoire totale utilisée / libre d'un programme peut être obtenue dans le programme via

java.lang.Runtime.getRuntime();

l'exécution a plusieurs méthodes qui se rapportent à la mémoire. L'exemple de codage suivant illustre son utilisation.

package test;

 import java.util.ArrayList;
 import java.util.List;

 public class PerformanceTest {
     private static final long MEGABYTE = 1024L * 1024L;

     public static long bytesToMegabytes(long bytes) {
         return bytes / MEGABYTE;
     }

     public static void main(String[] args) {
         // I assume you will know how to create a object Person yourself...
         List < Person > list = new ArrayList < Person > ();
         for (int i = 0; i <= 100000; i++) {
             list.add(new Person("Jim", "Knopf"));
         }
         // Get the Java runtime
         Runtime runtime = Runtime.getRuntime();
         // Run the garbage collector
         runtime.gc();
         // Calculate the used memory
         long memory = runtime.totalMemory() - runtime.freeMemory();
         System.out.println("Used memory is bytes: " + memory);
         System.out.println("Used memory is megabytes: " + bytesToMegabytes(memory));
     }
 }
4
répondu nazar_art 2013-05-18 15:18:08

j'ai eu de très bons résultats avec le java .lang.instrument.Instrumentation approche mentionnée dans une autre réponse. Pour de bons exemples de son utilisation, voir l'entrée, Instrumentation Memory Counter de la Newsletter des Javaspecalists et le java.size of library on SourceForge.

3
répondu Matt Passell 2008-11-04 01:27:30

il semble que chaque objet possède un overhead de 16 octets sur les systèmes 32 bits (et 24 octets sur les systèmes 64 bits).

http://algs4.cs.princeton.edu/14analysis/ est une bonne source d'information. Un exemple parmi beaucoup de bons est le suivant.

enter image description here

http://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf est aussi très instructif, par exemple:

enter image description here

3
répondu Arun 2015-05-05 21:49:26

non, 100 petits objets ont besoin de plus d'information (mémoire) qu'un gros.

2
répondu Burkhard 2008-11-03 08:27:12

dans le cas où il est utile à quelqu'un, vous pouvez télécharger à partir de mon site web un petit agent Java pour interroger l'utilisation de la mémoire d'un objet . Il vous permettra d'interroger" profonde " utilisation de la mémoire ainsi.

2
répondu Neil Coffey 2009-04-07 17:10:51

la question sera très large.

cela dépend de la variable de classe ou vous pouvez appeler comme les états de l'utilisation de la mémoire en java.

il a également un besoin supplémentaire de mémoire pour les en-têtes et le référencement.

la mémoire tas utilisée par un objet Java inclut

  • mémoire pour les champs primitifs, selon leur taille (Voir ci-dessous pour les tailles de types primitifs);

  • mémoire pour les champs de référence (4 octets chacun);

  • en-tête d'objet, constitué de quelques octets de renseignements "administratifs";

objets en java nécessite également quelques informations "d'entretien", tels que l'enregistrement de la classe d'un objet, ID et les indicateurs de statut tels que si l'objet est actuellement accessible, actuellement synchronisation-verrouillé etc.

objet Java-tête de taille varie sur 32 bits et 64 bits de la jvm.

bien que ce soient les principaux consommateurs de mémoire jvm nécessite également des champs supplémentaires parfois comme pour l'alignement du code E. T. C.

tailles de types primitifs

boolean & octet -- 1

char & court -- 2

int & float -- 4

long & double -- 8

2
répondu Nikhil Agrawal 2013-05-18 14:23:18

les règles sur la quantité de mémoire consommée dépendent de l'implémentation JVM et de l'architecture CPU (32 bits contre 64 bits par exemple).

Pour les règles détaillées pour la JVM de SUN cochez la case mon ancien blog

en ce qui Concerne, Markus

1
répondu kohlerm 2011-08-24 10:01:45