web-dev-qa-db-fra.com

Calculer la taille de l'objet dans Java

Je veux enregistrer combien de mémoire (en octets, espérons-le) un objet prend pour un projet (je compare les tailles des structures de données) et il semble qu'il n'y ait aucune méthode pour le faire en Java. Censément, C/C++ a la méthode sizeOf(), mais elle n’existe pas en Java. J'ai essayé d'enregistrer la mémoire libre dans la machine virtuelle avec Runtime.getRuntime().freeMemory() avant et après la création de l'objet, puis d'enregistrer la différence, mais cela ne donnerait que 0 ou 131304, et rien entre les deux, quel que soit le nombre d'éléments dans la structure. . Aidez-moi, s'il vous plaît!

143
Tyler Petrochko

Vous pouvez utiliser le package Java.lang.instrumentation:

http://docs.Oracle.com/javase/7/docs/api/Java/lang/instrument/Instrumentation.html

Il a une méthode qui peut être utilisée pour obtenir l’approximation spécifique à la mise en œuvre de la taille de l’objet, ainsi que la surcharge associée à l’objet.

La réponse que Sergey a liée a un excellent exemple, que je vais republier ici, mais vous auriez déjà dû regarder à partir de 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);
    }
}

Utilisez getObjectSize:

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

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

La source:

En Java, quel est le meilleur moyen de déterminer la taille d'un objet?

82
Hunter McMillen

Regardez dans https://github.com/DimitrisAndreou/memory-measurer Guava l'utilise en interne, et ObjectGraphMeasurer est particulièrement simple à utiliser immédiatement, sans argument particulier 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));
  }
}
76
Louis Wasserman

La classe Java.lang.instrument.Instrumentation fournit un moyen simple d'obtenir la taille d'un objet Java, mais vous devez définir un premain et exécuter votre programme avec un Java. _ agent. Ceci est très ennuyeux lorsque vous n'avez besoin d'aucun agent et que vous devez alors fournir un agent factice pour votre application.

J'ai donc eu une solution alternative en utilisant la classe Unsafe à partir 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 la taille d'un objet Java. Dans l'exemple ci-dessous, j'utilise une classe auxiliaire UtilUnsafe pour obtenir une référence à l'objet Sun.misc.Unsafe.

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() { }
}
16
Miguel Gamboa

Une recherche google de "Java sizeof" a abouti à un article de Nice 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 cet article décrit deux manières d'obtenir la taille en octets de vos classes instanciées.

2
John