Получите размер объекта Java без использования Instrumentation api [duplicate]

Исключение нулевого указателя - это индикатор того, что вы используете объект, не инициализируя его.

Например, ниже - класс ученика, который будет использовать его в нашем коде.

public class Student {

    private int id;

    public int getId() {
        return this.id;
    }

    public setId(int newId) {
        this.id = newId;
    }
}

Приведенный ниже код дает вам исключение с нулевым указателем.

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}

Поскольку вы используете Obj_Student, но вы забыли инициализировать его, как в правильном коде, показанном ниже:

public class School {

    Student obj_Student;

    public School() {
        try {
            obj_Student = new Student();
            obj_Student.setId(12);
            obj_Student.getId();
        }
        catch(Exception e) {
            System.out.println("Null Pointer ");
        }
    }
}
547
задан Jeffrey Bosboom 4 May 2015 в 00:49
поделиться

24 ответа

Вы можете использовать пакет java.lang.instrument

Скомпилировать и поместить этот класс в 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);
    }
}

Добавить следующее в MANIFEST.MF:

Premain-Class: ObjectSizeFetcher

Использовать getObjectSize:

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

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

Вызывать с помощью:

java -javaagent:ObjectSizeFetcherAgent.jar C
408
ответ дан Ravindra babu 19 August 2018 в 12:31
поделиться
  • 1
    @Stefan Хороший намек! Можете ли вы рассказать, какими будут размеры byte[0], byte[1], byte[5], int[0], int[1], int[2], используя описанный вами подход? Было бы неплохо, если бы результаты включали накладные расходы для длины массива и выравнивания памяти. – dma_k 8 March 2010 в 12:28
  • 2
    Я попробовал это и получил странные и бесполезные результаты. Строки всегда были 32, независимо от их размера. Я думал, что это, возможно, размер указателя, но для другого неизменяемого класса, который я создал, я получил 24. Он хорошо работает для примитивов, но тогда вам действительно не нужна программа, чтобы рассказать вам, насколько велик символ. – Brel 16 September 2011 в 13:39
  • 3
    @Brel это решение является лишь «приближением объема хранения, потребляемого указанным объектом», как указано в документации. Также я полагаю, что авторы решили установить размер строки как 32 байта (только указатель?) Из-за пула строк в Java, что затрудняет утверждение, используется ли экземпляр String (хранится в пуле) или локальный и уникальный для класса. – Andrei I 17 July 2013 в 09:33
  • 4
    Как я могу использовать объект ObjectSizeFetcher, если не экспортировать jar? У меня есть тестовый Java-проект в eclipse. – Yura Shinkarev 5 August 2013 в 19:40
  • 5
    что, если я использую tomcat, это то же самое? Когда я добавляю Premain-Class: ObjectSizeFetcher в MANIFEST.MF в webcontent- gt; meta-inf- & gt; manifest.mf, и я запускаю планировщик для проверки моего размера объекта в ecplise, исключение из "Illegal access: этот экземпляр веб-приложения уже остановлен. Не удалось загрузить файл wodinow.weixin.jaskey.util.ObjectSizeFetcher. Исключением является java.lang.IllegalStateException & quot; бросается – Jaskey 25 July 2014 в 08:38

Просто используйте Java визуальную виртуальную машину.

В нем есть все, что нужно для анализа и отладки памяти.

Он также имеет консоль OQL (Object Query Language), которая позволяет вам делать много полезных вещей, одним из которых является sizeof(o)

2
ответ дан ACV 19 August 2018 в 12:31
поделиться

Мой ответ основан на коде, предоставленном Ником. Этот код измеряет общее количество байтов, которые заняты сериализованным объектом. Таким образом, это фактически измеряет размер сериализации stuff + plain object memory (просто сериализуйте, например, int, и вы увидите, что общее количество сериализованных байтов не 4). Поэтому, если вы хотите получить необработанный байтовый номер, используемый именно для вашего объекта, вам нужно немного изменить этот код. Например:

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

}

Я тестировал это решение с примитивными типами, String и некоторыми тривиальными классами. Также могут быть и не рассмотренные случаи.

UPDATE: пример изменен для поддержки вычисления размера памяти объектов массива.

0
ответ дан Agnius Vasiliauskas 19 August 2018 в 12:31
поделиться

Когда я работал в Twitter, я написал утилиту для вычисления размера большого объекта. Он учитывает различные модели памяти (32-разрядные, сжатые oops, 64-bit), padding, subclass padding, корректно работает с круговыми структурами данных и массивами. Вы можете просто скомпилировать этот .java-файл; он не имеет внешних зависимостей:

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

18
ответ дан Attila Szegedi 19 August 2018 в 12:31
поделиться
  • 1
    Szia! Я просто хотел бы выкрикнуть вашу презентацию : слайды 15-20 отлично подходят, чтобы помочь инстинктивно почувствовать стоимость различных решений в области данных. Спасибо, что опубликовали это! – Luke Usherwood 1 October 2015 в 01:58
  • 2
    "он не имеет внешних зависимостей & quot; - с каких пор guava не является внешней зависимостью? – l4mpi 11 January 2016 в 15:21
  • 3
    выглядит очень похоже на github.com/JetBrains/jdk8u_nashorn/blob/master/src/jdk/nashorn/… ? : O – Francesco 24 October 2017 в 14:02
  • 4
    Гуава - внешняя зависимость. – Mert Serimer 14 December 2017 в 11:33

Несколько лет назад Javaworld опубликовала статью об определении размера составных и потенциально вложенных объектов Java , они в основном проходят через создание реализации sizeof () в Java. Этот подход в основном основывается на другой работе, где люди экспериментально идентифицируют размер примитивов и типичных объектов Java, а затем применяют это знание к методу, который рекурсивно ходит по графу объектов, чтобы подсчитать общий размер.

Это всегда происходит быть несколько менее точным, чем нативная реализация C, просто из-за того, что происходит за кулисами класса, но это должен быть хороший индикатор.

Альтернативно проект SourceForge соответствующим образом называется sizeof , который предлагает библиотеку Java5 с реализацией sizeof ().

PS Не используйте сериализационный подход, нет никакой корреляции между размером сериализованного объекта и объемом памяти, который он потребляет в режиме реального времени.

69
ответ дан Boris Terzic 19 August 2018 в 12:31
поделиться

Существует также инструмент Memory Measurer (ранее в Google Code , теперь на GitHub ), который прост и опубликован под коммерческой версией лицензии Apache 2.0, так как обсуждался в аналогичном вопросе .

Он также требует аргумент командной строки для интерпретатора java, если вы хотите измерить потребление байта памяти, но в противном случае он работает нормально , по крайней мере, в сценариях, которые я использовал.

6
ответ дан Community 19 August 2018 в 12:31
поделиться
  • 1
    Ссылка мертва на сегодняшний день – Alfabravo 2 December 2015 в 16:00
  • 2
    По-видимому, он был удален из Google Code, но на GitHub еще есть копия. Еще очень полезный инструмент. Ссылка обновлена, спасибо. – PNS 17 December 2015 в 01:01

Вы должны измерить его с помощью инструмента или оценить его вручную, и это зависит от используемой вами JVM.

Существует некоторая фиксированная накладная плата для каждого объекта. Это JVM-специфический, но я обычно оцениваю 40 байт. Затем вам нужно взглянуть на членов класса. Ссылки на объекты - это 4 (8) байта в 32-битной (64-разрядной) JVM. Примитивные типы:

  • boolean и byte: 1 byte
  • char и short: 2 байта
  • int и float: 4 байта
  • long и double: 8 bytes

Массивы следуют тем же правилам; то есть это ссылка на объект, так что в вашем объекте принимает 4 (или 8) байта, а затем его длина умножается на размер его элемента.

Попытка сделать это программно с помощью вызовов Runtime.freeMemory() просто не дает вам большой точности из-за асинхронных вызовов сборщика мусора и т. д. Профилирование кучи с помощью -Xrunhprof или других инструментов даст вам наиболее точные результаты.

8
ответ дан erickson 19 August 2018 в 12:31
поделиться
  • 1
    @erickson Я не был бы уверен в sizeof (boolean) == 1, смотря на этот поток ( stackoverflow.com/questions/1907318/… ). Не могли бы вы прокомментировать это? – dma_k 8 March 2010 в 12:22
  • 2
    @dma_k, Java фактически не имеет реальных булевых элементов. Размер булевых составляет 4 байта вне массивов и 1 байт в пределах boolean[]. На самом деле все примитивы non double / long types составляют 4 байта. Последние равны 8 (ответ ошибочно ставит их также как 4) – bestsss 25 December 2012 в 16:43
  • 3
    @bestsss К сожалению, это была опечатка. Спасибо, что указали это. – erickson 26 December 2012 в 06:04
  • 4
    @bestsss: точнее, минимальное распределение памяти зависит от платформы и реализации JVM. Также объекты на куче выравниваются, поэтому после суммирования всех размеров нужно округлить. – dma_k 29 December 2012 в 11:52

Вот утилита, которую я сделал с использованием некоторых связанных примеров для обработки 32-битных, 64-битных и 64-битных со сжатым ООП. Он использует sun.misc.Unsafe.

Он использует Unsafe.addressSize() для получения размера собственного указателя и Unsafe.arrayIndexScale( Object[].class ) для размера ссылки на Java.

Он использует смещение поля известного класса для определения базового размера объекта.

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 );
    }
}
2
ответ дан Gwenc37 19 August 2018 в 12:31
поделиться
  • 1
    Вы тестировали этот класс со значениями? Я пробовал, но для меня неправильные значения !!!. – Débora 17 August 2014 в 15:26
  • 2
    Значения, которые он дал мне для простого объекта, были правильными, но отключены в 10 раз для списка, содержащего 1mio-объекты. Тем не менее, очень хорошая работа! – Michael Böckling 21 August 2014 в 14:12
  • 3
    Интересно. Я тестировал его с помощью JDK7u67, на Windows 7 x64 и Linux 2.6.16 / x86_64, используя каждый из 32-битных / 64-битных / адресных режимов. Я сравнил его с дампами памяти, проанализированными в Eclipse Memory Analyzer 1.3.x. Какую настройку вы используете? У вас есть конкретный пример, который я мог бы попробовать? – dlaudams 9 September 2014 в 06:43
  • 4
  • 5

Я написал быстрый тест один раз, чтобы оценить «на лету»:

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

}

Общая концепция - выделить объекты и измерить изменение свободного пространства кучи. Ключ getFreeMemory(), который запрашивает выполнение GC и ожидает, что размер свободной кучи будет стабилизирован. Вывод выше:

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

Это то, что мы ожидаем, учитывая поведение выравнивания и возможные служебные данные заголовка блока кучи.

Метод инструментария, подробно описанный в принятом ответе здесь Наиболее точный. Метод, который я описал, является точным, но только в контролируемых условиях, когда другие нити не создают / не отбрасывают объекты.

2
ответ дан Jason C 19 August 2018 в 12:31
поделиться

Вам нужно пройти объекты, используя отражение. Будьте осторожны, как и вы:

  • Простое выделение объекта имеет некоторые накладные расходы в JVM. Сумма зависит от JVM, поэтому вы можете сделать это значение параметром. По крайней мере, сделать его постоянным (8 байтов?) И применить к чему-либо выделенному.
  • Просто потому, что byte теоретически 1 байт не означает, что он занимает только один в памяти.
  • В объектных ссылках будут циклы, поэтому вам нужно будет сохранить HashMap или somesuch с использованием объектных равных в качестве компаратора для исключения бесконечных циклов.

@jodonnell: Мне нравится простота вашего решения, но многие объекты не являются Serializable (поэтому это порождает исключение), поля могут быть временными, а объекты могут переопределять стандартные методы.

9
ответ дан Jason Cohen 19 August 2018 в 12:31
поделиться
  • 1
    Не являются ли размеры различных примитивов, определенных в спецификации Java? (§2.4.1) – erickson 9 September 2008 в 18:25
  • 2
    Не в смысле «сколько памяти оно занимает», это вопрос. Только в том смысле, как они действуют. Например, байты, символы и шорты занимают целые слова в стеке Java, даже если они работают с округлением и т. Д. – Jason Cohen 9 September 2008 в 18:27
  • 3
    Это похоже на измерение размера, как показано Хайнцем в его Бюллетене № 78: javaspecialists.eu/archive/Issue078.html . Я использовал его. Его подход работает. – Peter Kofler 21 March 2010 в 10:26

Вы должны использовать jol - инструмент, разработанный как часть проекта OpenJDK.

JOL (Макет объекта Java) - это крошечный инструментарий для анализа схем компоновки объектов в JVM. Эти инструменты используют Unsafe, JVMTI и Serviceability Agent (SA) в значительной степени для декодирования фактического макета объекта, следа и ссылок. Это делает JOL гораздо более точным, чем другие инструменты, основанные на дампах кучи, предположениях спецификации и т. Д.

Чтобы получить размеры примитивов, ссылок и элементов массива, используйте VMSupport.vmDetails(). В Oracle JDK 1.8.0_40, работающем на 64-разрядной Windows (используется для всех следующих примеров), этот метод возвращает

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]

. Вы можете получить мелкий размер экземпляра объекта, используя ClassLayout.parseClass(Foo.class).toPrintable() (необязательно прохождение экземпляр к toPrintable). Это только пространство, потребляемое одним экземпляром этого класса; он не включает никаких других объектов, на которые ссылается этот класс. Он делает включением служебных данных VM для заголовка объекта, выравнивания полей и заполнения. Для 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

Вы можете получить сводный вид глубокого размера экземпляра объекта с помощью GraphLayout.parseInstance(obj).toFootprint(). Конечно, некоторые объекты в области отпечатков могут быть разделены (также ссылаются на другие объекты), поэтому это чрезмерное приближение пространства, которое можно было бы вернуть, когда этот объект собирает мусор. Для результата Pattern.compile("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$") (взятого из этого ответа ) jol сообщает об общей глубине 1840 байт, из которых только 72 являются самим экземпляром шаблона.

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)

Если вы вместо этого используете GraphLayout.parseInstance(obj).toPrintable(), jol сообщит вам адрес, размер, тип, значение и путь разметки полей для каждого объекта, на который ссылается, хотя это, как правило, слишком много деталей, чтобы быть полезным. Для текущего примера шаблонов вы можете получить следующее. (Адреса, скорее всего, будут меняться между прогонами.)

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)

Элементы «(что-то еще)» описывают другие объекты в куче, которые не являются частью этого графа объектов .

Лучшая jol-документация - это образцы jol в репозитории jol. Образцы демонстрируют общие операции jol и показывают, как вы можете использовать jol для анализа внутренних компонентов VM и сборщика мусора.

61
ответ дан Jeffrey Bosboom 19 August 2018 в 12:31
поделиться
  • 1
    Этот ответ должен иметь больше оборотов. Определенно очень хороший вариант для проверки. EDIT: проверено, что это было добавлено в этом году, в то время как вопрос был задан в '08. Вероятно, лучший и самый простой способ сделать то, что ОП задал в данный момент. – rents 30 August 2015 в 19:22
  • 2
    Автор инструмента написал сообщение в блоге о Jol . – Mike 6 September 2015 в 00:37
  • 3
    Для определения размера объекта "obj" Использование: org.openjdk.jol.info.GraphLayout.parseInstance (OBJ) .totalSize (); – vigor 19 January 2017 в 10:26
  • 4
    Возникает ли при использовании? – Jus12 25 March 2017 в 07:46
  • 5
    Обратите внимание, что vmDetails теперь VM.current().details(). – Miha_x64 13 May 2018 в 07:35

Я сомневаюсь, что вы хотите сделать это программно, если только вы не захотите сделать это один раз и сохраните его для использования в будущем. Это дорого стоить. В Java нет оператора sizeof (), и даже если бы он был, он учитывал бы только стоимость ссылок на другие объекты и размер примитивов.

Один из способов сделать это - сериализовать вещь в файл и посмотрите размер файла, например:

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

Конечно, это предполагает, что каждый объект отличается и не содержит непереходных ссылок на что-либо еще.

Еще одна стратегия заключалась бы в том, чтобы взять каждый объект и изучить его членов путем отражения и добавить размеры (boolean & amp; byte = 1 byte, short & amp; char = 2 байта и т. д.), работая по-вашему вниз по иерархии членства. Но это утомительно и дорого и заканчивается тем же, что и стратегия сериализации.

-6
ответ дан jodonnell 19 August 2018 в 12:31
поделиться
  • 1
    Я бы сериализовал его на байт [], используя ByteArrayOutputStream. Это будет намного быстрее, чем записать его в файл. – ScArcher2 9 September 2008 в 18:21
  • 2
    Почему этот ответ был опущен так много раз? – Koray Tugay 19 December 2015 в 18:20
  • 3
    @KorayTugay Определение размера байта объекта уже является дорогостоящей операцией. Написание каждого объекта на диск, чтобы определить размер, просто сделает его обход ... – HammerNL 19 December 2017 в 11:24
  • 4
    Сериализованный формат объекта полностью отличается от формата объекта в кучевой памяти. В частности, дескриптор класса объекта (и всех его сериализуемых суперклассов) записывается в поток. Таким образом, запись простого экземпляра java.lang.Integer создает около 80 байт, где представление кучи обычно равно 32 (в отличие от представления потока объектов, представление кучи зависит от размеров указателя и выравнивания объекта). Напротив, сериализованная ссылка null требует одного байта вместо четырех или восьми байтов в кучевой памяти. – Holger 9 May 2018 в 11:50

Вы можете сгенерировать кучу кучи (например, с помощью jmap), а затем проанализировать вывод, чтобы найти размеры объектов. Это автономное решение, но вы можете изучить мелкие и глубокие размеры и т. Д.

0
ответ дан JZeeb 19 August 2018 в 12:31
поделиться

Этот ответ не связан с размером объекта, но когда вы используете массив для размещения объектов; сколько объема памяти он выделит для объекта.

Таким образом, массивы, список или карта всех этих коллекций не будут храниться на самом деле (только во время примитивов реальный размер памяти объекта необходимо), он будет хранить только ссылки для этих объектов.

Теперь Used heap memory = sizeOfObj + sizeOfRef (* 4 bytes) in collection

  • (4/8 байт) зависит от (32/64 бит) ОС

PRIMITIVES

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

ОБЪЕКТЫ

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.

Я хочу сказать, что для всего объекта REFERENCE требуется только 4 байта памяти. Это может быть ссылка на String или ссылка на Double object, но зависит от создания объекта. Необходимая память будет меняться.

например) Если я создаю объект для нижележащего класса ReferenceMemoryTest, тогда 4 + 4 + 4 = 12 байтов памяти будет создана. При попытке инициализации ссылок память может отличаться.

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

Поэтому, когда создается массив объектов / ссылок, все его содержимое будет занято ссылками NULL. И мы знаем, что для каждой ссылки требуется 4 байта.

И, наконец, выделение памяти для кода ниже 20 байт.

ReferenceMemoryTest ref1 = new ReferenceMemoryTest (); (4 (ref1) + 12 = 16 байт) ReferenceMemoryTest ref2 = ref1; (4 (ref2) + 16 = 20 байт)

0
ответ дан Kanagavelu Sugumar 19 August 2018 в 12:31
поделиться
  • 1
    Как 4-байтовое целое число и ссылка на объект неизвестного размера вписываются в 4 байта? – user207421 4 May 2015 в 01:14
  • 2
    @EJP Я хочу сказать, что для всего объекта REFERENCE требуется только 4 байта памяти. Это может быть ссылка на String OR Double Reference, но зависит от создания объекта. – Kanagavelu Sugumar 4 May 2015 в 04:50

Класс java.lang.instrument.Instrumentation обеспечивает хороший способ получить размер Java-объекта, но для этого требуется определить premain и запустить вашу программу с помощью java-агента. Это очень скучно, когда вам не нужен какой-либо агент, а затем вам нужно предоставить фиктивный агент Jar для вашего приложения.

Итак, я получил альтернативное решение, использующее класс Unsafe из sun.misc. Итак, учитывая выравнивание кучи объектов в соответствии с архитектурой процессора и вычисление максимального смещения поля, вы можете измерить размер объекта Java. В приведенном ниже примере я использую вспомогательный класс UtilUnsafe для получения ссылки на объект 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() { }
}
6
ответ дан Miguel Gamboa 19 August 2018 в 12:31
поделиться
  • 1
    Интересный подход, но разве это не означает, что объект и его хранилища полей не фрагментированы? – nicoulaj 11 June 2012 в 14:25
  • 2
    Да, и я не знаю никакой реализации JVM, которая делает такую ​​фрагментацию. – Miguel Gamboa 18 June 2012 в 17:44
  • 3
    Я не понимаю. Фрагментация - это не вариант. Давайте возьмем пример объекта C, который хранится как поле объектов A и B. Не смещает ли он все это ни в A, ни в B? – nicoulaj 19 June 2012 в 14:46
  • 4
    Извините, но я не понимаю ни вашей точки зрения. Согласно моей интерпретации, объекты Java не могут храниться внутри других объектов, например, происходят с структурами C или типами значений в .Net. Поэтому, когда вы говорите: «объект C, который хранится как поле объектов A и B», означает, что объекты A и B имеют поля, которые хранят ссылки (указатели) на объект C. Тогда размер A и B равен смещение этого поля плюс размер ссылки (указатель) на объект C. И размер ссылки - это размер одного слова. – Miguel Gamboa 19 June 2012 в 15:24
  • 5
    О, хорошо, мы говорим о мелком размере. Виноват. – nicoulaj 19 June 2012 в 15:48

Без необходимости возиться с инструментами и т. д., и если вам не нужно знать размер байта для конкретного объекта, вы можете пойти со следующим подходом:

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

do your job here

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

как вы читаете использованную память до и после, и вызывая GC непосредственно перед тем, как получить используемую память, вы понижаете «шум» почти до 0.

. Для более надежного результата вы можете выполнять свою работу n раз, а затем разделить используемую память на n, получив, сколько занимает память. Более того, вы можете запускать все это больше времени и делать среднее.

3
ответ дан reallynice 19 August 2018 в 12:31
поделиться
  • 1
    Downvoter: помогите объяснить, почему? – reallynice 22 June 2016 в 08:10
  • 2
    Не означает ли System.gc(), что вы хотите использовать GC? Не гарантируется, что GC вообще называется. – Raildex 11 January 2017 в 14:42
  • 3
    @действительно мило. Это небезопасно, потому что вы никогда не можете использовать GC или влиять на память между вашими линиями. Таким образом, "между" два метода freeMemory GC могут освободить больше места, которое вы не считаете, таким образом, ваш объект будет выглядеть меньше – Mert Serimer 14 December 2017 в 11:37
  • 4
    @MertSerimer & quot; небезопасно & quot; для меня совершенно разный: в лучшем случае это не так точно, как я уже сказал. Кроме того, вы не можете управлять GC (как заявил Raildex), но для этого случая я также предложил вставить это в цикл. Это просто быстрая и грязная и приблизительная система, которая работает, если результат не должен быть очень надежным, как указано. – reallynice 14 December 2017 в 15:34

Большая часть других ответов дает мелкие размеры - например, размер HashMap без каких-либо ключей или значений, что маловероятно, что вы хотите.

Проект jamm использует пакет java.lang.instrumentation выше, но идет по дереву и поэтому может дать вам использование глубокой памяти.

new MemoryMeter().measureDeep(myHashMap);

https://github.com/jbellis/jamm

13
ответ дан rich 19 August 2018 в 12:31
поделиться

Я рекомендую библиотеку java-sizeof для поиска моркови. Это очень просто.

Вы можете получить его в maven:

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

. Только одна строка кода возвращает байты объекта:

RamUsageEstimator.sizeOf(new Object());

Вы можете увидеть исходный код в https://github.com/dweiss/java-sizeof

И есть презентация от автора библиотеки 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
ответ дан Rony Bichler 19 August 2018 в 12:31
поделиться

Нет вызова метода, если это то, о чем вы просите. С небольшими исследованиями, я полагаю, вы могли бы написать свои собственные. Конкретный экземпляр имеет фиксированный размер, полученный из числа ссылок и примитивных значений, а также учетных данных экземпляра. Вы просто будете ходить по графу объектов. Чем меньше типов строк, тем легче.

Если это слишком медленно или просто больше проблем, чем это стоит, всегда есть хорошее старомодное правило подсчета строк.

1
ответ дан sblundy 19 August 2018 в 12:31
поделиться

Для JSONObject приведенный ниже код может вам помочь.

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

возвращает размер в байтах

Я проверил его с моим объектом JSONArray, записав его в файл. Это дает размер объекта.

-3
ответ дан solokiran 19 August 2018 в 12:31
поделиться
  • 1
    это будет работать только для объектов, которые в основном являются строками. – Dexter Legaspi 7 May 2018 в 21:12

Я случайно нашел java-класс «jdk.nashorn.internal.ir.debug.ObjectSizeCalculator», уже в jdk, который прост в использовании и кажется весьма полезным для определения размера объекта.

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

:

164192
48
16
48
416
39
ответ дан Tom 19 August 2018 в 12:31
поделиться
  • 1
    То же самое здесь, я пытался другие решения, предложенные выше, и наткнулся на ObjectSizeCalculator. Я считаю, что никто не упоминал, если раньше, поскольку он был недавно представлен на JDK 8 в рамках проекта Nashorn . Однако я не нашел официальной документации по этому классу в Интернете. – Henrique Gontijo 16 October 2016 в 18:26
  • 2
    Кажется, он не рассматривает длины строк. Это примерно размер в стеке? – jontejj 7 May 2017 в 08:50
  • 3
    У меня есть hashmap, где com.carrotsearch.RamUsageEstimator возвращает около половины ObjectSizeCalculator. Какая из них истинна? - Какой из них более надежный? – badera 18 May 2017 в 08:36
  • 4
    Обратите внимание, что ObjectSizeCalculator поддерживается только на виртуальной машине HotSpot – kellanburket 2 February 2018 в 22:04

Во-первых, «размер объекта» не является четко определенной концепцией Java. Вы могли бы означать сам объект, с его членами, объектом и всеми объектами, на которые он ссылается (ссылочный граф). Вы можете указать размер в памяти или размер на диске. И JVM разрешено оптимизировать такие вещи, как Strings.

Итак, единственный правильный способ - спросить JVM с хорошим профилировщиком (я использую YourKit ), что, вероятно,

Однако из приведенного выше описания кажется, что каждая строка будет автономной и не имеет большого дерева зависимостей, поэтому метод сериализации, вероятно, будет хорошим приближением для большинства JVM , Самый простой способ сделать это:

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

Помните, что если у вас есть объекты с общими ссылками, это не даст дать правильный результат, а размер сериализации не будет всегда соответствуют размеру в памяти, но это хорошее приближение. Код будет немного более эффективным, если вы инициализируете размер ByteArrayOutputStream до разумного значения.

56
ответ дан u32i64 19 August 2018 в 12:31
поделиться
  • 1
    Мне нравится этот подход. Как далеко от размера объекта вы были отключены. – Berlin Brown 24 July 2009 в 18:56
  • 2
    Очень простой и эффективный. Другие методы слишком грязные (особенно внутри Eclipse RCP). Благодарю. – marcolopes 24 April 2012 в 17:18
  • 3
    Сериализация не будет отслеживать переходные переменные, а метод сериализации по умолчанию записывает строки в UTF-8, поэтому любые символы ANSI будут принимать только один байт. Если у вас много строк, ваш размер будет настолько далек, чтобы быть бесполезным. – TMN 9 July 2012 в 19:45
  • 4
    в то время как это может не дать точный размер, для моих нужд мне нужно было только сравнение между 2 объектами, а SizeOf не будет инициализироваться из веб-приложения. Благодаря! – Isaac 31 October 2012 в 00:57
  • 5
    Неправильно, рассмотрите, например, переходные поля. – Nitsan Wakart 29 April 2016 в 07:23
Размер
long heapSizeBefore = Runtime.getRuntime().totalMemory();

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

дает вам увеличение использования памяти jvm из-за создания объекта и обычно это размер объекта.

0
ответ дан user835199 19 August 2018 в 12:31
поделиться
  • 1
    что, если GC работает в середине во время // кода для построения объекта? Теперь вы можете дать правильный результат все время. – rajugaadu 17 June 2014 в 03:35

Если вам просто хотелось бы узнать, сколько памяти используется в вашей JVM и сколько бесплатно, вы можете попробовать что-то вроде этого:

// 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: Я думал, что это может быть полезно, поскольку автор вопроса также заявил, что хотел бы иметь логику, которая обрабатывает «чтение как можно большего количества строк, пока я не использовал 32 МБ памяти».

32
ответ дан Yuval 19 August 2018 в 12:31
поделиться
  • 1
    Это нехорошее решение, поскольку вы никогда не знаете, когда произойдет сбор мусора, или сколько дополнительной памяти будет выделено куче сразу. – Nick Fortescue 9 September 2008 в 18:24
  • 2
    Это правда, и я бы не хотел, чтобы это касалось основного вопроса этой должности, но это могло бы помочь ему знать программно, когда он приближается к максимальному размеру кучи. – matt b 9 September 2008 в 18:25
  • 3
    Другая проблема этого решения заключается в том, что вы находитесь в многопоточной среде (например, на веб-сервере). Возможно, что другие потоки выполнялись и потребляли память. С этим приближением вы вычисляете используемую память на всей виртуальной машине. – angelcervera 24 February 2013 в 12:34
  • 4
    Другим недостатком является то, что freeMemory возвращает приближение. Попробуйте создать объект javax.crypto.Cipher. Разница между двумя вызовами freeMemory (для оценки размера Cipher) не является постоянной! – Eugen 9 May 2013 в 16:08
  • 5
    Привет, почему heapSize + heapFreeSize & lt; heapMaxSize? – Jaskey 18 July 2014 в 06:38
Другие вопросы по тегам:

Похожие вопросы: