168 votes

Calculer la taille d'un objet en Java

Je veux enregistrer la quantité de mémoire (en octets, si possible) qu'un objet occupe pour un projet (je compare les tailles des structures de données) et il semble qu'il n'existe aucune méthode pour le faire en Java. Apparemment, le C/C++ dispose de sizeOf() mais cette méthode est inexistante en Java. J'ai essayé d'enregistrer la mémoire libre dans la JVM avec Runtime.getRuntime().freeMemory() avant et après la création de l'objet, puis en enregistrant la différence, mais elle ne donne que 0 ou 131304, et rien entre les deux, quel que soit le nombre d'éléments de la structure. Aidez-moi, s'il vous plaît !

6 votes

1 votes

Vous pouvez essayer totalMemory() et ensuite freeMemory() et les soustraire à la place.

5 votes

Je vous recommande de jeter un coup d'œil à Jbellis JAMM. ( github.com/jbellis/jamm ) Il s'appuie sur l'agent d'instrumentation mentionné ci-dessus mais encapsule quelques utilitaires utiles pour mesurer en profondeur l'empreinte d'un graphe d'objets entier. Cela me semble simple et plutôt cool.

98voto

Hunter McMillen Points 17717

Vous pouvez utiliser le java.lang.instrumentation paquet.

Il possède une méthode qui peut être utilisée pour obtenir l'approximation spécifique à l'implémentation de la taille de l'objet, ainsi que l'overhead associé à l'objet.

La réponse dont Sergey a donné le lien contient un excellent exemple, que je vais reprendre ici, mais que vous auriez déjà dû examiner dans son commentaire :

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

Utilice getObjectSize :

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

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

Source :

1 votes

Il est dit : "La seule façon d'accéder à une instance de l'interface Instrumentation est de lancer la JVM d'une manière qui indique la classe d'agent - voir la spécification du paquet. L'instance d'Instrumentation est transmise à la méthode premain de la classe d'agent. Une fois qu'un agent acquiert l'instance Instrumentation, il peut appeler des méthodes sur l'instance à tout moment. " <-- comment faire (dans Eclipse) ?

0 votes

Ne dois-je pas spécifier comment la JVM est lancée ? J'ai essayé et j'obtiens toujours une NullPointerException.

2 votes

Modifiez votre message ci-dessus avec ce que vous avez essayé.

83voto

Louis Wasserman Points 67557

Regardez dans https://github.com/DimitrisAndreou/memory-measurer .
Guava l'utilise en interne, et ObjectGraphMeasurer est particulièrement simple à utiliser, sans arguments spéciaux en ligne de commande.

import objectexplorer.ObjectGraphMeasurer;

public class Measurer {

  public static void main(String[] args) {
    Set<Integer> hashset = new HashSet<Integer>();
    Random random = new Random();
    int n = 10000;
    for (int i = 1; i <= n; i++) {
      hashset.add(random.nextInt());
    }
    System.out.println(ObjectGraphMeasurer.measure(hashset));
  }
}

0 votes

C'était plutôt utile. Même l'autre a été très facile à faire fonctionner. L'avez-vous déjà utilisé ?

1 votes

J'ai déjà utilisé memory-measurer, oui. (Je contribue à Guava, et j'ai mentionné que nous l'utilisons en interne. ;) )

0 votes

Réponse instantanée. C'est pour ça que j'aime SO. Merci beaucoup. J'essaie de l'utiliser pour mesurer une activité de mémoire. C'est très pratique.

16voto

Miguel Gamboa Points 808

El java.lang.instrument.Instrumentation offre un bon moyen d'obtenir la taille d'un objet Java, mais elle exige que vous définissiez une classe premain et exécutez votre programme avec un agent java. C'est très ennuyeux lorsque vous n'avez pas besoin d'agent et que vous devez alors fournir un agent Jar factice à votre application.

J'ai donc trouvé une solution alternative en utilisant le Unsafe de la classe sun.misc . Ainsi, en considérant l'alignement du tas d'objets selon l'architecture du processeur et en calculant le décalage maximal des champs, vous pouvez mesurer la taille d'un objet Java. Dans l'exemple ci-dessous, j'utilise une classe auxiliaire UtilUnsafe pour obtenir une référence à la 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() { }
}

0 votes

Je ne suis pas sûr de ceci : ((int)maxOffset/WORD) + 1)*WORD, mais je pense que cela fonctionne car je suis presque sûr que les variables 64 bits ne traversent jamais une frontière de 8 octets dans une VM 64 bits. Bon code sinon, bien que vous pourriez bien sûr vous débarrasser de toute la carte en faisant des efforts. J'ai créé ma propre version qui gère également les tableaux d'objets ici : tinybrain.de/1011517 (il faudrait encore ajouter des tableaux primitifs).

4voto

Claudio Points 831

Je vous recommande de jeter un coup d'œil à Jbellis JAMM. ( https://github.com/jbellis/jamm ) Il s'appuie sur l'agent d'instrumentation mentionné ci-dessus mais encapsule quelques utilitaires utiles pour mesurer en profondeur l'empreinte d'un graphe d'objets entier. Cela me semble simple et plutôt cool.

2voto

John Points 171

Une recherche google de "Java sizeof" a donné lieu à un bel article sur Java sizeof sur javaworld. En fait, une lecture intéressante.

Pour répondre à votre question, il n'y a pas d'équivalent Java de "sizeof()", mais l'article décrit quelques façons d'obtenir la taille en octets de vos classes instanciées.

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