modifier la taille d'un jpanel java




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

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 ne cause pas OutOfMemoryError . Chaque ligne se traduit par un objet. Y at-il un moyen facile de trouver la taille de cet objet par programmation? Existe-t-il une référence qui définit la taille des types primitifs et des références d'objet pour une VM ?

À l'heure actuelle, j'ai un code qui dit lire jusqu'à 32 000 lignes , mais j'aimerais aussi avoir du code qui dit lire autant de lignes que possible jusqu'à ce que j'ai utilisé 32 Mo de mémoire. Peut-être que c'est une question différente, mais j'aimerais quand même savoir.


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

Cela aussi, exige un argument de ligne de commande à l'interpréteur java si vous voulez mesurer la consommation d'octets de la mémoire, mais semble autrement fonctionner très bien, au moins dans les scénarios que je l'ai utilisé.


Il y a quelques années, Javaworld avait un article sur la détermination de la taille des objets Java composites et potentiellement imbriqués , ils marchent essentiellement à travers 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 de manière récursive un graphe d'objet afin d'obtenir la taille totale.

Il sera toujours un peu moins précis qu'une mise en œuvre en 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 correctement appelé sizeof 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 lorsqu'il est en ligne.


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

Vous pouvez l'obtenir en maven:

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

C'est seulement une ligne de code qui retourne les octets d'un objet:

RamUsageEstimator.sizeOf(new Object());

Vous pouvez voir le code source sur 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


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

J'ai donc eu une solution alternative en utilisant la classe Unsafe de sun.misc . Ainsi, compte tenu de l'alignement des tas d'objets en fonction de l'architecture du processeur et du calcul du 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() { }
}

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

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

Cependant, d'après la description ci-dessus, il semble que chaque ligne soit autonome et ne possède 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, cela ne donnera pas le bon résultat, 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 la taille ByteArrayOutputStream à une valeur sensible.


Quand j'ai travaillé sur Twitter, j'ai écrit un utilitaire pour calculer la taille de l'objet profond. Il prend en compte différents modèles de mémoire (32 bits, compression oups, 64 bits), le remplissage, le remplissage des sous-classes, fonctionne correctement sur les structures de données circulaires et les tableaux. Vous pouvez simplement compiler ce 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


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 un surcoût fixe par objet. C'est spécifique à JVM, mais j'évalue habituellement 40 octets. Ensuite, vous devez regarder les membres de la classe. Les références d'objet sont de 4 (8) octets dans une machine virtuelle Java 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 qu'il s'agit d'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 programme avec des appels à Runtime.freeMemory() ne vous donne 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.


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

  • Le simple fait d'allouer un objet a une surcharge dans la machine virtuelle Java. La quantité varie en fonction de la machine virtuelle Java, de sorte que vous puissiez faire de cette valeur un paramètre. Au moins en faire une constante (8 octets?) Et appliquer à tout ce qui est alloué.
  • Juste parce que byte est théoriquement 1 octet ne signifie pas qu'il n'en prend qu'un en mémoire.
  • Il y aura des boucles dans les références d'objets, donc vous devrez garder une HashMap ou quelque chose en utilisant object-equals comme comparateur pour éliminer les boucles infinies.

@jodonnell: J'aime la simplicité de votre solution, mais beaucoup d'objets ne sont pas Serializable (donc cela lancerait une exception), les champs peuvent être transitoires, et les objets peuvent remplacer les méthodes standard.


Vous pouvez utiliser le package java.lang.instrument

Compilez et mettez cette classe dans un fichier 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

Here is a utility I made using some of the linked examples to handle 32-bit, 64-bit and 64-bit with compressed OOP. It uses sun.misc.Unsafe .

It uses Unsafe.addressSize() to get the size of a native pointer and Unsafe.arrayIndexScale( Object[].class ) for the size of a Java reference.

It uses the field offset of a known class to work out the base size of an object.

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

I wrote a quick test once to estimate on the fly:

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

}

General concept is allocate objects and measure change in free heap space. The key being getFreeMemory() , which requests GC runs and waits for the reported free heap size to stabilize . The output of the above is:

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

Which is what we expect, given alignment behavior and possible heap block header overhead.

The instrumentation method detailed in the accepted answer here the most accurate. The method I described is accurate but only under controlled conditions where no other threads are creating/discarding objects.


Just use java visual VM.

It has everything you need to profile and debug memory problems.

It also has a OQL (Object Query Language) console which allows you to do many useful things, one of which being sizeof(o)


The below code can help you surely.

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

returns size in bytes

I checked it with my JSONArray object by writing it to a file. It is giving object size.


There isn't a method call, if that's what you're asking for. With a little research, I suppose you could write your own. A particular instance has a fixed sized derived from the number of references and primitive values plus instance bookkeeping data. You would simply walk the object graph. The less varied the row types, the easier.

If that's too slow or just more trouble than it's worth, there's always good old-fashioned row counting rule-of-thumbs.


Without having to mess with instrumentation and so on, and if you don't need to know the byte-exact size of an object, you could go with the following approach:

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

do your job here

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

This way you read the used memory before and after, and calling the GC just before getting the used memory you lower the "noise" almost to 0.

For a more reliable result you can run your job n times, and then divide the used memory by n, obtaining how much memory one run takes. Even more, you can run the whole thing more times and make an average.


You could generate a heap dump (with jmap, for example) and then analyze the output to find object sizes. This is an offline solution, but you can examine shallow and deep sizes, etc.





memory