En Java, quelle est la meilleure façon de déterminer la taille d'un objet?


Par exemple, disons que j'ai une application qui peut lire dans un fichier CSV avec des piles de lignes de données. Je donne à l'utilisateur un résumé du nombre de lignes en fonction des types de données, mais je veux m'assurer que je ne lis pas trop de lignes de données et que je provoque OutOfMemoryErrors. Chaque ligne se traduit par un objet. Existe-t-il un moyen facile de connaître la taille de cet objet par programme? Existe-t-il une référence qui définit la taille des types primitifs et des références d'objets pour un VM?

Droite maintenant, j'ai un code qui dit lire jusqu'à 32 000 lignes) , mais j'aimerais aussi avoir un code qui dit lire autant de lignes que possible jusqu'à ce que j'ai utilisé 32 MO de la mémoire. C'est peut-être une question différente, mais j'aimerais toujours savoir.

Author: Jeffrey Bosboom, 2008-09-09

24 answers

Vous pouvez utiliser le java.lang.ensemble d'instruments

Compiler et mettre cette classe dans un JAR:

import java.lang.instrument.Instrumentation;

public class ObjectSizeFetcher {
    private static Instrumentation instrumentation;

    public static void premain(String args, Instrumentation inst) {
        instrumentation = inst;
    }

    public static long getObjectSize(Object o) {
        return instrumentation.getObjectSize(o);
    }
}

Ajoutez ce qui suit à votre MANIFEST.MF:

Premain-Class: ObjectSizeFetcher

Utilisez getObjectSize:

public class C {
    private int x;
    private int y;

    public static void main(String [] args) {
        System.out.println(ObjectSizeFetcher.getObjectSize(new C()));
    }
}

Invoquer avec:

java -javaagent:ObjectSizeFetcherAgent.jar C
 417
Author: Stefan Karlsson, 2016-06-28 18:24:59

Il y a quelques années, Javaworld avaitun article sur la détermination de la taille des objets Java composites et potentiellement imbriqués , ils parcourent essentiellement la création d'une implémentation sizeof() en Java. L'approche s'appuie essentiellement sur d'autres travaux où les gens ont identifié expérimentalement la taille des primitives et des objets Java typiques, puis appliquent ces connaissances à une méthode qui parcourt récursivement un graphique d'objet pour calculer la taille totale.

Il va toujours être un peu moins précis qu'une implémentation C native simplement à cause des choses qui se passent dans les coulisses d'une classe, mais cela devrait être un bon indicateur.

Alternativement, un projet SourceForge appelé de manière appropriéesizeof qui offre une bibliothèque Java5 avec une implémentation sizeof ().

PS N'utilisez pas l'approche de sérialisation, il n'y a pas de corrélation entre la taille d'un objet sérialisé et la quantité de mémoire qu'il consomme en direct.

 70
Author: Boris Terzic, 2008-09-09 18:42:54

, Vous devez utiliser jol, un outil développé dans le cadre du projet OpenJDK.

JOL (Java Object Layout) est la petite boîte à outils pour analyser les schémas de disposition d'objets dans les JVM. Ces outils utilisent fortement Unsafe, JVMTI et Serviceability Agent (SA) pour décoder la disposition, l'empreinte et les références des objets réels. Cela rend JOL beaucoup plus précis que d'autres outils reposant sur des décharges de tas, des hypothèses de spécification, etc.

Pour obtenir les tailles des primitives, références et éléments de tableau, utilisez VMSupport.vmDetails(). Sur Oracle JDK 1.8.0_40 s'exécutant sur Windows 64 bits (utilisé pour tous les exemples suivants), cette méthode renvoie

Running 64-bit HotSpot VM.
Using compressed oop with 0-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]

Vous pouvez obtenir la taille superficielle d'une instance d'objet en utilisant ClassLayout.parseClass(Foo.class).toPrintable() (en passant éventuellement une instance à toPrintable). Il ne s'agit que de l'espace consommé par une seule instance de cette classe; il n'inclut aucun autre objet référencé par cette classe. Il inclut la surcharge de la machine virtuelle pour l'en-tête de l'objet, l'alignement des champs et le remplissage. Pour java.util.regex.Pattern:

java.util.regex.Pattern object internals:
 OFFSET  SIZE        TYPE DESCRIPTION                    VALUE
      0     4             (object header)                01 00 00 00 (0000 0001 0000 0000 0000 0000 0000 0000)
      4     4             (object header)                00 00 00 00 (0000 0000 0000 0000 0000 0000 0000 0000)
      8     4             (object header)                cb cf 00 20 (1100 1011 1100 1111 0000 0000 0010 0000)
     12     4         int Pattern.flags                  0
     16     4         int Pattern.capturingGroupCount    1
     20     4         int Pattern.localCount             0
     24     4         int Pattern.cursor                 48
     28     4         int Pattern.patternLength          0
     32     1     boolean Pattern.compiled               true
     33     1     boolean Pattern.hasSupplementary       false
     34     2             (alignment/padding gap)        N/A
     36     4      String Pattern.pattern                (object)
     40     4      String Pattern.normalizedPattern      (object)
     44     4        Node Pattern.root                   (object)
     48     4        Node Pattern.matchRoot              (object)
     52     4       int[] Pattern.buffer                 null
     56     4         Map Pattern.namedGroups            null
     60     4 GroupHead[] Pattern.groupNodes             null
     64     4       int[] Pattern.temp                   null
     68     4             (loss due to the next object alignment)
Instance size: 72 bytes (reported by Instrumentation API)
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total

Vous pouvez obtenir une vue récapitulative de la taille profonde d'une instance d'objet en utilisant GraphLayout.parseInstance(obj).toFootprint(). Bien sûr, certains objets de l'empreinte peuvent être partagés (également référencés à partir d'autres objets), c'est donc une surapproximation de l'espace qui pourrait être récupérée lorsque cet objet est collecté. Pour le résultat de Pattern.compile("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$") (tiré de cette réponse), jol rapporte une empreinte totale de 1840 octets, dont seulement 72 sont l'instance de modèle elle-même.

java.util.regex.Pattern instance footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1       112       112   [C
         3       272       816   [Z
         1        24        24   java.lang.String
         1        72        72   java.util.regex.Pattern
         9        24       216   java.util.regex.Pattern$1
        13        24       312   java.util.regex.Pattern$5
         1        16        16   java.util.regex.Pattern$Begin
         3        24        72   java.util.regex.Pattern$BitClass
         3        32        96   java.util.regex.Pattern$Curly
         1        24        24   java.util.regex.Pattern$Dollar
         1        16        16   java.util.regex.Pattern$LastNode
         1        16        16   java.util.regex.Pattern$Node
         2        24        48   java.util.regex.Pattern$Single
        40                1840   (total)

Si vous utilisez plutôt GraphLayout.parseInstance(obj).toPrintable(), jol vous indiquera l'adresse, la taille, le type, la valeur et le chemin des déréférences de champ pour chaque objet référencé, bien que ce soit généralement trop de détails pour être utile. Pour l'exemple de modèle en cours, vous pouvez obtenir ce qui suit. (Les adresses changeront probablement entre les exécutions.)

java.util.regex.Pattern object externals:
          ADDRESS       SIZE TYPE                             PATH                           VALUE
         d5e5f290         16 java.util.regex.Pattern$Node     .root.next.atom.next           (object)
         d5e5f2a0        120 (something else)                 (somewhere else)               (something else)
         d5e5f318         16 java.util.regex.Pattern$LastNode .root.next.next.next.next.next.next.next (object)
         d5e5f328      21664 (something else)                 (somewhere else)               (something else)
         d5e647c8         24 java.lang.String                 .pattern                       (object)
         d5e647e0        112 [C                               .pattern.value                 [^, [, a, -, z, A, -, Z, 0, -, 9, _, ., +, -, ], +, @, [, a, -, z, A, -, Z, 0, -, 9, -, ], +, \, ., [, a, -, z, A, -, Z, 0, -, 9, -, ., ], +, $]
         d5e64850        448 (something else)                 (somewhere else)               (something else)
         d5e64a10         72 java.util.regex.Pattern                                         (object)
         d5e64a58        416 (something else)                 (somewhere else)               (something else)
         d5e64bf8         16 java.util.regex.Pattern$Begin    .root                          (object)
         d5e64c08         24 java.util.regex.Pattern$BitClass .root.next.atom.val$rhs        (object)
         d5e64c20        272 [Z                               .root.next.atom.val$rhs.bits   [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
         d5e64d30         24 java.util.regex.Pattern$1        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e64d48         24 java.util.regex.Pattern$1        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs.val$rhs (object)
         d5e64d60         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e64d78         24 java.util.regex.Pattern$1        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$rhs (object)
         d5e64d90         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e64da8         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs.val$lhs (object)
         d5e64dc0         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs (object)
         d5e64dd8         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs        (object)
         d5e64df0         24 java.util.regex.Pattern$5        .root.next.atom                (object)
         d5e64e08         32 java.util.regex.Pattern$Curly    .root.next                     (object)
         d5e64e28         24 java.util.regex.Pattern$Single   .root.next.next                (object)
         d5e64e40         24 java.util.regex.Pattern$BitClass .root.next.next.next.atom.val$rhs (object)
         d5e64e58        272 [Z                               .root.next.next.next.atom.val$rhs.bits [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
         d5e64f68         24 java.util.regex.Pattern$1        .root.next.next.next.atom.val$lhs.val$lhs.val$lhs (object)
         d5e64f80         24 java.util.regex.Pattern$1        .root.next.next.next.atom.val$lhs.val$lhs.val$rhs (object)
         d5e64f98         24 java.util.regex.Pattern$5        .root.next.next.next.atom.val$lhs.val$lhs (object)
         d5e64fb0         24 java.util.regex.Pattern$1        .root.next.next.next.atom.val$lhs.val$rhs (object)
         d5e64fc8         24 java.util.regex.Pattern$5        .root.next.next.next.atom.val$lhs (object)
         d5e64fe0         24 java.util.regex.Pattern$5        .root.next.next.next.atom      (object)
         d5e64ff8         32 java.util.regex.Pattern$Curly    .root.next.next.next           (object)
         d5e65018         24 java.util.regex.Pattern$Single   .root.next.next.next.next      (object)
         d5e65030         24 java.util.regex.Pattern$BitClass .root.next.next.next.next.next.atom.val$rhs (object)
         d5e65048        272 [Z                               .root.next.next.next.next.next.atom.val$rhs.bits [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
         d5e65158         24 java.util.regex.Pattern$1        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e65170         24 java.util.regex.Pattern$1        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs.val$rhs (object)
         d5e65188         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs (object)
         d5e651a0         24 java.util.regex.Pattern$1        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$rhs (object)
         d5e651b8         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom.val$lhs.val$lhs (object)
         d5e651d0         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom.val$lhs (object)
         d5e651e8         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom (object)
         d5e65200         32 java.util.regex.Pattern$Curly    .root.next.next.next.next.next (object)
         d5e65220        120 (something else)                 (somewhere else)               (something else)
         d5e65298         24 java.util.regex.Pattern$Dollar   .root.next.next.next.next.next.next (object)

Les entrées "(something else)" décrivent d'autres objets dans le tas qui ne font pas partie de ce graphe d'objet.

La meilleure documentation jol est le échantillons jol dans le jol référentiel. Les exemples montrent les opérations jol courantes et montrent comment vous pouvez utiliser jol pour analyser les internes de VM et de garbage collector.

 63
Author: Jeffrey Bosboom, 2015-05-04 00:46:52

Premièrement, "la taille d'un objet" n'est pas un concept bien défini en Java. Vous pouvez signifier l'objet lui-même, avec seulement ses membres, l'Objet et tous les objets auxquels il se réfère (le graphique de référence). Vous pouvez signifier la taille en mémoire ou la taille sur le disque. Et la JVM est autorisée à optimiser des choses comme les chaînes.

Donc la seule façon correcte est de demander à la JVM, avec un bon profileur (j'utilise YourKit ), ce qui n'est probablement pas ce que vous voulez.

Cependant, d'après la description ci-dessus on dirait que chaque ligne sera autonome et n'aura pas un grand arbre de dépendance, donc la méthode de sérialisation sera probablement une bonne approximation sur la plupart des JVM. La façon la plus simple de le faire est la suivante:

 Serializable ser;
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 ObjectOutputStream oos = new ObjectOutputStream(baos);
 oos.writeObject(ser);
 oos.close();
 return baos.size();

Rappelez-vous que si vous avez des objets avec des références communes, ce ne donnera pas le résultat correct, et la taille de la sérialisation ne correspondra pas toujours à la taille en mémoire, mais c'est une bonne approximation. Le code sera un peu plus efficace si vous initialisez le ByteArrayOutputStream taille à une valeur raisonnable.

 56
Author: Nick Fortescue, 2018-02-03 15:52:59

, j'ai accidentellement trouvé une classe java "jdk. nashorn. internal. ir. debug. ObjectSizeCalculator", déjà dans jdk, ce qui est facile à utiliser et semble très utile pour déterminer la taille d'un objet.

System.out.println(ObjectSizeCalculator.getObjectSize(new gnu.trove.map.hash.TObjectIntHashMap<String>(12000, 0.6f, -1)));
System.out.println(ObjectSizeCalculator.getObjectSize(new HashMap<String, Integer>(100000)));
System.out.println(ObjectSizeCalculator.getObjectSize(3));
System.out.println(ObjectSizeCalculator.getObjectSize(new int[]{1, 2, 3, 4, 5, 6, 7 }));
System.out.println(ObjectSizeCalculator.getObjectSize(new int[100]));

Résultats:

164192
48
16
48
416
 44
Author: Tom, 2016-09-09 07:53:20

Si vous voudrais juste savoir combien de mémoire est utilisée dans votre JVM, et combien est libre, vous pouvez essayer quelque chose comme ceci:

// Get current size of heap in bytes
long heapSize = Runtime.getRuntime().totalMemory();

// Get maximum size of heap in bytes. The heap cannot grow beyond this size.
// Any attempt will result in an OutOfMemoryException.
long heapMaxSize = Runtime.getRuntime().maxMemory();

// Get amount of free memory within the heap in bytes. This size will increase
// after garbage collection and decrease as new objects are created.
long heapFreeSize = Runtime.getRuntime().freeMemory();

Edit: Je pensais que cela pourrait être utile car l'auteur de la question a également déclaré qu'il aimerait avoir une logique qui gère "lire autant de lignes que possible jusqu'à ce que j'ai utilisé 32 Mo de mémoire."

 33
Author: matt b, 2014-07-16 16:08:47

Quand je travaillais chez Twitter, j'ai écrit un utilitaire pour calculer la taille des objets profonds. Il prend en compte différents modèles de mémoire (32 bits, oops compressés, 64 bits), padding, padding de sous-classe, fonctionne correctement sur les structures de données circulaires et les tableaux. Vous pouvez simplement compiler celui-ci .fichier java; il n'a pas de dépendances externes:

Https://github.com/twitter/commons/blob/master/src/java/com/twitter/common/objectsize/ObjectSizeCalculator.java

 18
Author: Attila Szegedi, 2015-04-09 11:07:01

La plupart des autres réponses fournissent des tailles peu profondes - par exemple la taille d'un HashMap sans aucune des clés ou valeurs, ce qui n'est probablement pas ce que vous voulez.

Le projet jamm utilise le java.lang.le paquet d'instrumentation ci-dessus mais marche dans l'arbre et peut donc vous donner l'utilisation de la mémoire profonde.

new MemoryMeter().measureDeep(myHashMap);

Https://github.com/jbellis/jamm

 13
Author: rich, 2015-03-06 14:07:34

Vous devez parcourir les objets en utilisant la réflexion. Soyez prudent comme vous le faites:

  • Le simple fait d'allouer un objet a une surcharge dans la JVM. Le montant varie selon la JVM, vous pouvez donc faire de cette valeur un paramètre. Au moins en faire une constante (8 octets?) et appliquer à tout ce qui est alloué.
  • Ce n'est pas parce que byte est théoriquement 1 octet qu'il n'en prend qu'un en mémoire.
  • Il y aura des boucles dans les références d'objet, vous devrez donc garder un HashMap ou un certain en utilisant object-equals comme comparateur pour éliminer les boucles infinies.

@jodonnell: J'aime la simplicité de votre solution, mais de nombreux objets ne sont pas sérialisables (donc cela lèverait une exception), les champs peuvent être transitoires et les objets peuvent remplacer les méthodes standard.

 10
Author: Jason Cohen, 2008-09-09 17:19:48

Vous devez le mesurer avec un outil, ou l'estimer à la main, et cela dépend de la JVM que vous utilisez.

Il y a une surcharge fixe par objet. C'est spécifique à la JVM, mais j'estime généralement 40 octets. Ensuite, vous devez regarder les membres de la classe. Les références d'objet sont de 4 (8) octets dans une JVM 32 bits (64 bits). Les types primitifs sont:

  • booléen et octet: 1 octet
  • char et court: 2 octets
  • int et float: 4 octets
  • long et double: 8 octets

Les tableaux suivent les mêmes règles; c'est-à-dire que c'est une référence d'objet qui prend 4 (ou 8) octets dans votre objet, puis sa longueur multipliée par la taille de son élément.

Essayer de le faire par programmation avec des appels à Runtime.freeMemory() ne vous donne tout simplement pas beaucoup de précision, à cause des appels asynchrones au garbage collector, etc. Le profilage du tas avec-Xrunhprof ou d'autres outils vous donnera les résultats les plus précis.

 8
Author: erickson, 2012-12-26 04:04:16

Je recommande la bibliothèque java-sizeof pour carrotsearch. C'est très simple.

Vous pouvez l'obtenir dans maven:

 <dependency>
    <groupId>com.carrotsearch</groupId>
    <artifactId>java-sizeof</artifactId>
    <version>0.0.3</version>
</dependency>

Il n'y a qu'une seule ligne de code qui renvoie les octets d'un objet:

RamUsageEstimator.sizeOf(new Object());

Vous pouvez voir le code source à la https://github.com/dweiss/java-sizeof

Et il y a une présentation de l'auteur de la bibliothèque http://www.slideshare.net/DawidWeiss/sizeofobject-how-much-memory-objects-take-on-jvms-and-when-this-may-matter?ref=http://cheremin.blogspot.com/2012/05/how-much-memory-objects-take-on-jvm-and.html

 7
Author: Rony Bichler, 2016-11-23 12:14:17

La classe java.lang.instrument.Instrumentation fournit un bon moyen d'obtenir la taille d'un objet Java, mais elle vous oblige à définir un premain et à exécuter votre programme avec un agent java. C'est très ennuyeux lorsque vous n'avez besoin d'aucun agent et que vous devez fournir un agent Jar factice à votre application.

J'ai donc obtenu une solution alternative en utilisant la classe Unsafe du sun.misc. Ainsi, en considérant l'alignement du tas d'objets en fonction de l'architecture du processeur et en calculant le décalage de champ maximal, vous pouvez mesurer de la taille d'un Objet Java. Dans l'exemple ci-dessous, j'utilise une classe auxiliaire UtilUnsafe pour obtenir une référence à l' sun.misc.Unsafe objet.

private static final int NR_BITS = Integer.valueOf(System.getProperty("sun.arch.data.model"));
private static final int BYTE = 8;
private static final int WORD = NR_BITS/BYTE;
private static final int MIN_SIZE = 16; 

public static int sizeOf(Class src){
    //
    // Get the instance fields of src class
    // 
    List<Field> instanceFields = new LinkedList<Field>();
    do{
        if(src == Object.class) return MIN_SIZE;
        for (Field f : src.getDeclaredFields()) {
            if((f.getModifiers() & Modifier.STATIC) == 0){
                instanceFields.add(f);
            }
        }
        src = src.getSuperclass();
    }while(instanceFields.isEmpty());
    //
    // Get the field with the maximum offset
    //  
    long maxOffset = 0;
    for (Field f : instanceFields) {
        long offset = UtilUnsafe.UNSAFE.objectFieldOffset(f);
        if(offset > maxOffset) maxOffset = offset; 
    }
    return  (((int)maxOffset/WORD) + 1)*WORD; 
}
class UtilUnsafe {
    public static final sun.misc.Unsafe UNSAFE;

    static {
        Object theUnsafe = null;
        Exception exception = null;
        try {
            Class<?> uc = Class.forName("sun.misc.Unsafe");
            Field f = uc.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            theUnsafe = f.get(uc);
        } catch (Exception e) { exception = e; }
        UNSAFE = (sun.misc.Unsafe) theUnsafe;
        if (UNSAFE == null) throw new Error("Could not obtain access to sun.misc.Unsafe", exception);
    }
    private UtilUnsafe() { }
}
 6
Author: Miguel Gamboa, 2012-05-14 16:37:13

Il y a aussi l'outil Memory Measurer (anciennement à Google Code, maintenant sur GitHub), qui est simple et publié sous la licence commerciale Apache 2.0, comme discuté dans une question similaire.

Il nécessite également un argument de ligne de commande à l'interpréteur java si vous souhaitez mesurer la consommation d'octets de mémoire, mais semble fonctionner correctement, du moins dans les scénarios que je l'ai utilisés.

 6
Author: PNS, 2017-05-23 12:34:36

Voici un utilitaire que j'ai fait en utilisant certains des exemples liés pour gérer 32 bits, 64 bits et 64 bits avec OOP compressé. Il utilise sun.misc.Unsafe.

, Il utilise Unsafe.addressSize() pour obtenir la taille d'un pointeur natif et Unsafe.arrayIndexScale( Object[].class ) pour la taille de Java de référence.

Il utilise le décalage de champ d'une classe connue pour calculer la taille de base d'un objet.

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.IdentityHashMap;
import java.util.Stack;
import sun.misc.Unsafe;

/** Usage: 
 * MemoryUtil.sizeOf( object )
 * MemoryUtil.deepSizeOf( object )
 * MemoryUtil.ADDRESS_MODE
 */
public class MemoryUtil
{
    private MemoryUtil()
    {
    }

    public static enum AddressMode
    {
        /** Unknown address mode. Size calculations may be unreliable. */
        UNKNOWN,
        /** 32-bit address mode using 32-bit references. */
        MEM_32BIT,
        /** 64-bit address mode using 64-bit references. */
        MEM_64BIT,
        /** 64-bit address mode using 32-bit compressed references. */
        MEM_64BIT_COMPRESSED_OOPS
    }

    /** The detected runtime address mode. */
    public static final AddressMode ADDRESS_MODE;

    private static final Unsafe UNSAFE;

    private static final long ADDRESS_SIZE; // The size in bytes of a native pointer: 4 for 32 bit, 8 for 64 bit
    private static final long REFERENCE_SIZE; // The size of a Java reference: 4 for 32 bit, 4 for 64 bit compressed oops, 8 for 64 bit
    private static final long OBJECT_BASE_SIZE; // The minimum size of an Object: 8 for 32 bit, 12 for 64 bit compressed oops, 16 for 64 bit
    private static final long OBJECT_ALIGNMENT = 8;

    /** Use the offset of a known field to determine the minimum size of an object. */
    private static final Object HELPER_OBJECT = new Object() { byte b; };


    static
    {
        try
        {
            // Use reflection to get a reference to the 'Unsafe' object.
            Field f = Unsafe.class.getDeclaredField( "theUnsafe" );
            f.setAccessible( true );
            UNSAFE = (Unsafe) f.get( null );

            OBJECT_BASE_SIZE = UNSAFE.objectFieldOffset( HELPER_OBJECT.getClass().getDeclaredField( "b" ) );

            ADDRESS_SIZE = UNSAFE.addressSize();
            REFERENCE_SIZE = UNSAFE.arrayIndexScale( Object[].class );

            if( ADDRESS_SIZE == 4 )
            {
                ADDRESS_MODE = AddressMode.MEM_32BIT;
            }
            else if( ADDRESS_SIZE == 8 && REFERENCE_SIZE == 8 )
            {
                ADDRESS_MODE = AddressMode.MEM_64BIT;
            }
            else if( ADDRESS_SIZE == 8 && REFERENCE_SIZE == 4 )
            {
                ADDRESS_MODE = AddressMode.MEM_64BIT_COMPRESSED_OOPS;
            }
            else
            {
                ADDRESS_MODE = AddressMode.UNKNOWN;
            }
        }
        catch( Exception e )
        {
            throw new Error( e );
        }
    }


    /** Return the size of the object excluding any referenced objects. */
    public static long shallowSizeOf( final Object object )
    {
        Class<?> objectClass = object.getClass();
        if( objectClass.isArray() )
        {
            // Array size is base offset + length * element size
            long size = UNSAFE.arrayBaseOffset( objectClass )
                    + UNSAFE.arrayIndexScale( objectClass ) * Array.getLength( object );
            return padSize( size );
        }
        else
        {
            // Object size is the largest field offset padded out to 8 bytes
            long size = OBJECT_BASE_SIZE;
            do
            {
                for( Field field : objectClass.getDeclaredFields() )
                {
                    if( (field.getModifiers() & Modifier.STATIC) == 0 )
                    {
                        long offset = UNSAFE.objectFieldOffset( field );
                        if( offset >= size )
                        {
                            size = offset + 1; // Field size is between 1 and PAD_SIZE bytes. Padding will round up to padding size.
                        }
                    }
                }
                objectClass = objectClass.getSuperclass();
            }
            while( objectClass != null );

            return padSize( size );
        }
    }


    private static final long padSize( final long size )
    {
        return (size + (OBJECT_ALIGNMENT - 1)) & ~(OBJECT_ALIGNMENT - 1);
    }


    /** Return the size of the object including any referenced objects. */
    public static long deepSizeOf( final Object object )
    {
        IdentityHashMap<Object,Object> visited = new IdentityHashMap<Object,Object>();
        Stack<Object> stack = new Stack<Object>();
        if( object != null ) stack.push( object );

        long size = 0;
        while( !stack.isEmpty() )
        {
            size += internalSizeOf( stack.pop(), stack, visited );
        }
        return size;
    }


    private static long internalSizeOf( final Object object, final Stack<Object> stack, final IdentityHashMap<Object,Object> visited )
    {
        // Scan for object references and add to stack
        Class<?> c = object.getClass();
        if( c.isArray() && !c.getComponentType().isPrimitive() )
        {
            // Add unseen array elements to stack
            for( int i = Array.getLength( object ) - 1; i >= 0; i-- )
            {
                Object val = Array.get( object, i );
                if( val != null && visited.put( val, val ) == null )
                {
                    stack.add( val );
                }
            }
        }
        else
        {
            // Add unseen object references to the stack
            for( ; c != null; c = c.getSuperclass() )
            {
                for( Field field : c.getDeclaredFields() )
                {
                    if( (field.getModifiers() & Modifier.STATIC) == 0 
                            && !field.getType().isPrimitive() )
                    {
                        field.setAccessible( true );
                        try
                        {
                            Object val = field.get( object );
                            if( val != null && visited.put( val, val ) == null )
                            {
                                stack.add( val );
                            }
                        }
                        catch( IllegalArgumentException e )
                        {
                            throw new RuntimeException( e );
                        }
                        catch( IllegalAccessException e )
                        {
                            throw new RuntimeException( e );
                        }
                    }
                }
            }
        }

        return shallowSizeOf( object );
    }
}
 3
Author: dlaudams, 2014-06-26 06:02:35

Sans avoir à jouer avec l'instrumentation, etc., et si vous n'avez pas besoin de connaître la taille exacte d'un objet, vous pouvez suivre l'approche suivante:

System.gc();
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

do your job here

System.gc();
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

De cette façon, vous lisez la mémoire utilisée avant et après, et en appelant le GC juste avant d'obtenir la mémoire utilisée, vous réduisez le "bruit" presque à 0.

Pour un résultat plus fiable, vous pouvez exécuter votre travail n fois, puis diviser la mémoire utilisée par n, en obtenant la quantité de mémoire nécessaire à une exécution. Encore plus, vous pouvez courir le tout plus de fois et faire une moyenne.

 3
Author: reallynice, 2015-04-03 12:09:59

Il n'y a pas d'appel de méthode, si c'est ce que vous demandez. Avec un peu de recherche, je suppose que vous pourriez écrire votre propre. Une instance particulière a une taille fixe dérivée du nombre de références et de valeurs primitives plus les données de comptabilité d'instance. Vous marcheriez simplement le graphique d'objet. Moins les types de lignes sont variés, plus il est facile.

Si c'est trop lent ou juste plus de problèmes que ça en vaut la peine, il y a toujours de bonnes règles de comptage de lignes à l'ancienne.

 2
Author: sblundy, 2008-09-09 17:15:40

, j'ai écrit un test rapide une fois pour estimer à la volée:

public class Test1 {

    // non-static nested
    class Nested { }

    // static nested
    static class StaticNested { }

    static long getFreeMemory () {
        // waits for free memory measurement to stabilize
        long init = Runtime.getRuntime().freeMemory(), init2;
        int count = 0;
        do {
            System.out.println("waiting..." + init);
            System.gc();
            try { Thread.sleep(250); } catch (Exception x) { }
            init2 = init;
            init = Runtime.getRuntime().freeMemory();
            if (init == init2) ++ count; else count = 0;
        } while (count < 5);
        System.out.println("ok..." + init);
        return init;
    }

    Test1 () throws InterruptedException {

        Object[] s = new Object[10000];
        Object[] n = new Object[10000];
        Object[] t = new Object[10000];

        long init = getFreeMemory();

        //for (int j = 0; j < 10000; ++ j)
        //    s[j] = new Separate();

        long afters = getFreeMemory();

        for (int j = 0; j < 10000; ++ j)
            n[j] = new Nested();

        long aftersn = getFreeMemory();

        for (int j = 0; j < 10000; ++ j)
            t[j] = new StaticNested();

        long aftersnt = getFreeMemory();

        System.out.println("separate:      " + -(afters - init) + " each=" + -(afters - init) / 10000);
        System.out.println("nested:        " + -(aftersn - afters) + " each=" + -(aftersn - afters) / 10000);
        System.out.println("static nested: " + -(aftersnt - aftersn) + " each=" + -(aftersnt - aftersn) / 10000);

    }

    public static void main (String[] args) throws InterruptedException {
        new Test1();
    }

}

Le concept général est d'allouer des objets et de mesurer le changement dans l'espace de tas libre. La clé étant getFreeMemory(), qui demande des exécutions de GC et attend que la taille de tas libre rapportée se stabilise. La sortie de ce qui précède est:

nested:        160000 each=16
static nested: 160000 each=16

C'est ce que nous attendons, compte tenu du comportement d'alignement et de la surcharge possible de l'en-tête du bloc de tas.

La méthode d'instrumentation détaillée dans la réponse acceptée ici la plus précise. Le la méthode que j'ai décrite est précise mais uniquement dans des conditions contrôlées où aucun autre thread ne crée / rejette des objets.

 2
Author: Jason C, 2013-11-16 03:34:24

Utilisez simplement java visual VM.

Il a tout ce dont vous avez besoin pour profiler et déboguer les problèmes de mémoire.

Il dispose également d'une console OQL (Object Query Language) qui vous permet de faire de nombreuses choses utiles, dont sizeof(o)

 2
Author: ACV, 2018-03-23 11:53:26

Vous pouvez générer un vidage de tas (avec jmap, par exemple), puis analyser la sortie pour trouver la taille des objets. Ceci est une solution hors ligne, mais vous pouvez examiner les tailles peu profondes et profondes, etc.

 0
Author: JZeeb, 2013-04-04 15:08:07
long heapSizeBefore = Runtime.getRuntime().totalMemory();

// Code for object construction
...
long heapSizeAfter = Runtime.getRuntime().totalMemory();
long size = heapSizeAfter - heapSizeBefore;

Size vous donne l'augmentation de l'utilisation de la mémoire de la jvm due à la création d'objet et qui est généralement la taille de l'objet.

 0
Author: user835199, 2014-05-07 07:23:43

Ma réponse est basée sur le code fourni par Nick. Ce code mesure la quantité totale d'octets occupés par l'objet sérialisé. Donc, cela mesure en fait les choses de sérialisation + l'empreinte mémoire d'objet simple (il suffit de sérialiser par exemple int et vous verrez que la quantité totale d'octets sérialisés n'est pas 4). Donc, si vous voulez obtenir un numéro d'octet brut utilisé exactement pour votre objet, vous devez modifier un peu ce code. Comme ceci:

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class ObjectSizeCalculator {
    private Object getFirstObjectReference(Object o) {
        String objectType = o.getClass().getTypeName();

        if (objectType.substring(objectType.length()-2).equals("[]")) {
            try {
                if (objectType.equals("java.lang.Object[]"))
                    return ((Object[])o)[0];
                else if (objectType.equals("int[]"))
                    return ((int[])o)[0];
                else
                    throw new RuntimeException("Not Implemented !");
            } catch (IndexOutOfBoundsException e) {
                return null;
            }
        }

        return o;
    } 

    public int getObjectSizeInBytes(Object o) {
        final String STRING_JAVA_TYPE_NAME = "java.lang.String";

        if (o == null)
            return 0;

        String objectType = o.getClass().getTypeName();
        boolean isArray = objectType.substring(objectType.length()-2).equals("[]");

        Object objRef = getFirstObjectReference(o);
        if (objRef != null && !(objRef instanceof Serializable))
            throw new RuntimeException("Object must be serializable for measuring it's memory footprint using this method !");

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(o);
            oos.close();
            byte[] bytes = baos.toByteArray();

            for (int i = bytes.length - 1, j = 0; i != 0; i--, j++) {
                if (objectType != STRING_JAVA_TYPE_NAME) {
                    if (bytes[i] == 112)
                        if (isArray)
                            return j - 4;
                        else
                            return j;
                } else {
                    if (bytes[i] == 0)
                        return j - 1;
                }
            }
        } catch (Exception e) {
            return -1;
        }

        return -1;
    }    

}

J'ai testé cette solution avec primitifs types, Chaîne, et sur certaines classes triviales. Il peut y avoir des cas non couverts aussi.


MISE À JOUR: Exemple modifié pour prendre en charge le calcul de l'empreinte mémoire des objets du tableau.

 0
Author: Agnius Vasiliauskas, 2014-10-19 21:53:42

Cette réponse n'est pas liée à la taille de l'objet, mais lorsque vous utilisez un tableau pour accueillir les objets; combien de taille de mémoire il allouera à l'objet.

Donc les tableaux, la liste ou la carte de toutes ces collections ne stockeront pas vraiment d'objets (seulement au moment des primitives, la taille réelle de la mémoire d'objet est nécessaire), il ne stockera que des références pour ces objets.

Maintenant {le[3]}

  • (4/8 octets) dépend de (32/64 bits) OS

PRIMITIVES

int   [] intArray    = new int   [1]; will require 4 bytes.
long  [] longArray   = new long  [1]; will require 8 bytes.

OBJETS

Object[] objectArray = new Object[1]; will require 4 bytes. The object can be any user defined Object.
Long  [] longArray   = new Long  [1]; will require 4 bytes.

Je veux dire que toute la RÉFÉRENCE d'objet n'a besoin que de 4 octets de mémoire. Il peut s'agir d'une référence de chaîne OU d'une référence d'objet double, Mais dépend de la création de l'objet, la mémoire nécessaire varie.

Par exemple) Si je crée un objet pour la classe ci-dessous ReferenceMemoryTest alors 4 + 4 + 4 = 12 octets de mémoire seront créés. La mémoire peut varier lorsque vous essayez d'initialiser les références.

 class ReferenceMemoryTest {
    public String refStr;
    public Object refObj;
    public Double refDoub; 
}

Alors quand sont en train de créer un tableau objet/référence, tout son contenu sera occupé par des références NULLES. Et nous savons que chaque référence nécessite 4 octets.

Et enfin, l'allocation de mémoire pour le code ci-dessous est de 20 octets.

ReferenceMemoryTest ref1 = new ReferenceMemoryTest(); ( 4(ref1) + 12 = 16 octets) ReferenceMemoryTest ref2 = ref1; ( 4(ref2) + 16 = 20 octets)

 0
Author: Kanagavelu Sugumar, 2015-07-13 03:32:51

Pour JSONObject, le code ci-dessous peut vous aider.

`JSONObject.toString().getBytes("UTF-8").length`

Renvoie la taille en octets

Je l'ai vérifié avec mon objet JSONArray en l'écrivant dans un fichier. C'est en donnant la taille de l'objet.

 -3
Author: solokiran, 2018-08-01 15:56:11

Je doute que vous vouliez le faire par programme, sauf si vous voulez juste le faire une fois et le stocker pour une utilisation future. C'est un coûteuse. Il n'y a pas d'opérateur sizeof() en Java, et même s'il y en avait, il ne compterait que le coût des références à d'autres objets et la taille des primitives.

Une façon de le faire est de sérialiser la chose dans un fichier et de regarder la taille du fichier, comme ceci:

Serializable myObject;
ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream ("obj.ser"));
oos.write (myObject);
oos.close ();

Bien sûr, cela suppose que chaque objet est distinct et ne contient des références non transitoires à toute autre chose.

Une autre stratégie serait de prendre chaque objet et d'examiner ses membres par réflexion et d'additionner les tailles (boolean & byte = 1 octet, short & char = 2 octets, etc.), travaillant votre chemin dans la hiérarchie des membres. Mais c'est fastidieux et coûteux et finit par faire la même chose que la stratégie de sérialisation ferait.

 -6
Author: jodonnell, 2008-09-09 17:11:35