2012-02-20 15 views
106

Voglio registrare la quantità di memoria (in byte, si spera) che un oggetto occupa per un progetto (sto confrontando le dimensioni delle strutture dati) e sembra che non ci sia alcun metodo per farlo in Java. Presumibilmente, C/C++ ha il metodo sizeOf(), ma questo non esiste in Java. Ho provato a registrare la memoria libera nella JVM con Runtime.getRuntime().freeMemory() prima e dopo aver creato l'oggetto e quindi registrato la differenza, ma darebbe solo 0 o 131304 e nulla tra loro, indipendentemente dal numero di elementi nella struttura. Aiuto per favore!Calcola la dimensione dell'oggetto in Java

+4

http://stackoverflow.com/questions/52353/in-java-what-is-the-best-way-to-determine-the-size-of-an-object –

+0

Si consiglia di prova totalMemory() e quindi freeMemory() e sottrai invece quelli. – Matt

+2

Ti consiglio di dare un'occhiata a Jbellis JAMM. (https://github.com/jbellis/jamm) Fa affidamento sull'agente di strumentazione sopra menzionato, ma incapsula alcune utilità hepful per misurare in profondità l'impronta di un intero oggetto grafico. Sembra semplice e carino per me. – Claudio

risposta

68

È possibile utilizzare il pacchetto java.lang.instrumentation:

http://docs.oracle.com/javase/7/docs/api/java/lang/instrument/Instrumentation.html

Ha un metodo che può essere utilizzato per ottenere il ravvicinamento implementazione specifica della dimensione dell'oggetto, così come overhead associato all'oggetto.

La risposta che Sergey collegata ha un grande esempio, che io ripubblicare qui, ma si dovrebbe avere già guardato dal suo commento:

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

Uso getObjectSize:

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

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

fonte per esempio:

In Java, what is the best way to determine the size of an object?

+1

afferma "L'unico modo per accedere a un'istanza dell'interfaccia Instrumentation è che la JVM venga avviata in modo da indicare la classe dell'agente, consultare la specifica del pacchetto. L'istanza Instrumentation viene passata al metodo premain della classe agent. un agente acquisisce l'istanza Instrumentation, l'agente può chiamare metodi sull'istanza in qualsiasi momento. "<- Come faccio a farlo (in Eclipse)? –

+0

Non devo specificare come verrà lanciata la JVM? Ho provato e continua a darmi NullPointerException –

+1

Modifica il tuo post sopra con quello che hai provato. –

1

a google la ricerca di "Java sizeof" ha prodotto un bel articolo su Java sizeof su javaworld. In realtà, una lettura interessante.

Per rispondere alla tua domanda, non esiste un equivalente Java di "sizeof()", ma l'articolo descrive un paio di modi per ottenere la dimensione in byte delle classi istanziate.

65

Cerca in https://github.com/DimitrisAndreou/memory-measurer Guava lo utilizza internamente e ObjectGraphMeasurer è particolarmente semplice da utilizzare, senza alcuno speciale argomento della riga di comando.  

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

Questo è stato piuttosto utile. Anche l'altro è stato molto facile farlo funzionare. Hai usato questo prima? – Venki

+1

Ho usato misuratore di memoria prima, sì. (Contribuisco a Guava, e ho detto che lo usiamo internamente.;)) –

+0

Risposta immediata. è per questo che amo così tanto. grazie mille Sto cercando di usarlo per misurare un'attività di memoria. è diventato molto utile. – Venki

14

La classe java.lang.instrument.Instrumentation fornisce un bel modo per ottenere la dimensione di un oggetto Java, ma si richiede di definire un premain ed eseguire il programma con un agente Java. Questo è molto noioso quando non hai bisogno di alcun agente e quindi devi fornire un agente fittizio Jar alla tua applicazione.

Quindi ho ottenuto una soluzione alternativa utilizzando la classe Unsafe da sun.misc. Pertanto, considerando l'allineamento degli heap degli oggetti in base all'architettura del processore e il calcolo dell'offset del campo massimo, è possibile misurare la dimensione di un oggetto Java. Nell'esempio seguente utilizzo una classe ausiliaria UtilUnsafe per ottenere un riferimento all'oggetto 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() { } 
} 
+0

Non ne sono sicuro: ((int) maxOffset/WORD) + 1) * WORD, ma penso che funzioni anche perché sono abbastanza sicuro che le variabili a 64 bit non incrocino mai un limite di 8 byte in un 64 bit VM. Buon codice altrimenti, anche se ovviamente potreste sbarazzarvi dell'intera mappa facendo sforzi. Ho creato la mia versione che gestisce anche gli array di oggetti qui: http://tinybrain.de/1011517 (avrebbe ancora bisogno di aggiungere matrici primitive). –

Problemi correlati