Сколько занимает памяти объект пустой класс c

Обновлено: 08.07.2024

Механизм автоматического управления памятью Java ( automatic storage management system known as a garbage collector ) Экономит много времени при написании кода, значительно повышает производительность Java, а производительность JVM становится все лучше и лучше, особенноG1Появление улучшенной сборки мусора stop the world Ситуация.

Может быть, многие люди не рассматривали эту проблему, Сколько памяти занимает объект Object (Object obj = new Object ())?

Здесь ясно, что объект является ссылкой на объект ( reference - there are three kinds of reference types: class types,array types, and interface types), Длина ссылки определяет адресуемость Java, 32-битный JDK составляет 4 байта, 64-битный JDK составляет 8 байтов (Когда указатель не сжат)。

Поскольку объект obj не имеет никаких данных (поля), Будет ли выделено место в куче? Если место выделено, что в нем хранится?

Анализируя с помощью объектно-ориентированного мышления, объект инкапсулирует данные и поведение и представляет собой единое целое, хотя объект obj не имеет данных, он имеет поведение (класс Object определяет 12 методов). Когда мы выполняем новую операцию, значение obj является адресом памяти кучи, так как obj указывает на блок памяти, это означает Выделим для этого место в куче A.

Так сколько места выделено и что хранится? вThe Java Virtual Machine Specification Java SE 7 EditionиThe Java Language Specification Java SE 7 EditionВ нем не найдено соответствующего описания, которое, вероятно, относится к категории свободного контроля над JVM. Мы можем использовать jvisualvm.exe, который поставляется с JDK, чтобы проверить, сколько места выделено. Чтобы легко проверить, сколько памяти занимает объект в jvisualvm, вместо Object используется закрытый статический внутренний класс EmptyObject. Поскольку определение класса пустое, вы можете обращаться с EmptyObject и Object эквивалентно.

Здесь мы анализируем использование памяти различным количеством новых объектов (для циклов): новый 1 объект - 16 байт, новые 2 объекта - 32 байта, новые 100 объектов - 1600 байт, и многие передачи Попытки, мы можем видеть из jvisualvm Количество байтов = количество объектов * 16 У нас есть основания полагать, что количество объектов и количество байтов Линейные отношения , Отсюда видно, что объем памяти, отображаемый jvisualvm, не имеет ничего общего с указанными 4 или 8 байтами, то есть jvisualvm отображает объем памяти кучи, что также хорошо понимается. Размещение фиксировано. 8 байтов - это ссылки, 16 байтов - это куча памяти, всего 8 + 16 = 24 байта, поэтому Новый объект Object занимает 8 + 16 = 24 байта (64-битный JDK) 。

Если JDK 32-битный, в соответствии с методом анализа выше Новый объект Object занимает 4 + 8 = 12 байт (32-битный JDK) , Как показано ниже:

64-битный JDK:

32-битный JDK:

Тем не менее, мы все еще можем сделать смелое предположение: с помощью приведенного выше сравнительного анализа размера кучи 64-битной и 32-битной памяти было обнаружено, что размер выделения кучи в два раза больше, чем у эталонного. пример, Как записать ? Поскольку объект класса размещается в области метода, сам объект класса является объектом, поэтому на него можно ссылаться с помощью ссылки, поэтому в памяти кучи могут быть две ссылки, указывающие на два объекта. После анализа здесь все становится более понятным: в памяти кучи может быть два адреса памяти, один из которых указывает на EmptyObject.class (в экспериментальном коде используйте EmptyObject вместо Object), на что один указывает? Не уверен!

вInside the Java 2 Virtual Machine Такое описание есть в п.5.5.5 Билла Веннерса:

The Java virtual machine specification is silent on how objects should be represented on the heap. Object representation--an integral aspect of the overall design of the heap and garbage collector--is a decision of implementation designers.

Что ж, наконец-то все стало ясно. Спецификация JVM не определяет, как объекты Java представляются в куче. Представление объектов является неотъемлемой частью общего проекта кучи и сборщика мусора. Это определяется разработчиком реализации JVM. а. Поэтому, если мы действительно хотим выяснить, как представлены объекты, нам нужно запросить виртуальную машину HotSpot или другие материалы, связанные с реализацией JVM.








У нас может не быть никакого практического значения для изучения того, сколько памяти занимает объект Object, потому что мы можем определить дерево объектов при программировании и в основном определить размер объекта. В дополнение к полям переменной длины, конечно, у нас обычно есть ограничения длины для полей переменной длины. Так что нас действительно волнует конечный размер всех данных, который является размером базы данных.

Объектно-ориентированный анализ, дизайн и программирование пакет "Бонг Вэй Гуй" слоистый «Это важнейший критерий проектирования в архитектурном дизайне. Потому что только таким образом мы можем добиться базового разделения, сделать возможным совместное разделение труда и удовлетворить промышленные требования». Максимизировать производительность Конечная цель.

Так почему мы должны изучать этот вопрос без практического значения? Я думаю, что это можно описать только тремя словами: любознательность 。Любопытство - это мощный толчок, который подталкивает нас к исследованиям технологий. Когда мы много лет работали, особенно в компаниях, которые не ценят технологии, у нас все еще есть страсть к технологиям? Держите чуткое и любопытное сердце, возможно, путь к технологиям может идти дольше и дальше.

Цель этой статьи - показать идею анализа проблемы, сделать смелые предположения, тщательно проверить доказательства, проследить источник и процитировать Священные Писания. Способы проверки: найдите стандартные спецификации, найдите классические авторитетные книги, проведите собственные эксперименты, найдите исходный код и т. Д.

Когда мы создаем переменную int var = 5 , все понятно, компьютер берет (выделяет) память 32 бита и записывает туда значение 5 в двоичном виде.

Но что происходит когда мы создаем переменную типа класс? class a = 5 . Что происходит? Сколько байт выделяется под эту переменную?

11.8k 2 2 золотых знака 13 13 серебряных знаков 26 26 бронзовых знаков


В первом случае ничего не понятно, так как размер типа int и количество реально выделяемой под него памяти определяется компилятором. Во втором случае ошибка синтаксиса. class a = 5 - такого в С++ не бывает. class - это ключевое слово и оно не может быть использовано таким образом . @VTT почему пишут такое? "myVar1 = 25; Указывает компьютеру, что нужно выделить память для переменной myVar1 типа int. Размер памяти выделяемой для нее зависит от самого компьютера. Например на 32-х разрядном компьютере он равен 4 байтам(32 бит)." myVar1 = 25; можно написать только для уже ранее объявленной переменной. Поэтому не не ясно о каком "указывает компьютеру, что нужно выделить память" вы ведете речь. Нет, ничего подобного это не указывает. При создании экземпляра класса автоматически запускается конструктор, который может делать с памятью что угодно, хоть всю память зарезервировать.

Объект в стеке

В программе выделяется столько байт, сколько требуется для хранения данных экземпляра данного класса. Например, объект пустого класс займёт один байт, если в нём хранится int , то его размер прибавится к размеру объекта класса. Вот интересный код для исследования этих свойств:

Результат выполнения с моим компилятором:

Меняя число переменных можно заметить, что поля с модификатором static не влияют на размер выделенной памяти, что и логично, ведь она не относится к конкретным экземплярам класса.

Объект в куче

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

Получается даже, что размер указателя может быть больше самого объекта:


9,309 5 5 золотых знаков 21 21 серебряный знак 50 50 бронзовых знаков

В первом случае - int var = 5; - компилятор выделяет sizeof(int) байтов памяти под переменную var . Это совсем не обязательно 32 бита.

Во втором случае - Class a = 5; - компилятор точно таким же образом выделяет sizeof(Class) байтов под переменную a . Все совершенно единообразно.

Выделение памяти в таких примерах никоим образом не зависит правой части данного объявления, т.е. = 5 никак не влияет на размер выделяемой памяти.

А затем, когда память уже выделена, значение 5 используется в качестве инициализатора для нового объекта. Как именно оно используется - зависит от конкретного типа. В первом случае оно просто заносится в переменную var . А что произойдет во втором случае уже зависит от деталей типа Class . Инициализация в С++ - процесс, описываемый целым набором весьма запутанных правил.

мне было интересно, что может быть размер объекта пустого класса. Она, конечно, могла бы!--4-->не быть 0 байт, так как должно быть возможно ссылаться и указывать на него, как на любой другой объект. Но насколько велик такой объект?

я использовал эту небольшую программу:

вывод, который я получил на компиляторах Visual C++ и Cygwin-g++, был 1 байт! Это было немного удивительно для меня, так как я ожидал, что он будет размером с машинного слова (32 бита или 4 байта).

может ли кто-нибудь объяснить почему размер 1 байт? почему 4 байта? Зависит ли это от компилятора или от машины? Кроме того, может ли кто-нибудь дать более убедительную причину, почему пустой объект класса не будет иметь размер 0 байт?

цитирую стиль и техника C++ Бьярне Страуструпа FAQ, причина, по которой размер не равен нулю, заключается в том, "чтобы гарантировать, что адреса двух разных объектов будут разными."И размер может быть 1, потому что выравнивание здесь не имеет значения, так как на самом деле смотреть не на что.

стандарт утверждает, что все большинство производных объектов имеют sizeof () > = 1:

это действительно деталь реализации. Когда-то давно я думал, что это может быть ноль байтов или тысяча байтов, что это не имеет никакого отношения к спецификации языка. Но, посмотрев на стандарт (раздел 5.3.3), sizeof определяется как всегда возвращающий один или больше, независимо от того, что.

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

это необходимо, среди прочего, для того, чтобы вы могли обрабатывать массивы объектов и указатели на них. Если вашим элементам было разрешено иметь нулевой размер, то &(array[0]) будет идентично &(array[42]) , что вызовет всевозможные разрушения в ваших циклах обработки.

причина, по которой это может быть не машинное слово, заключается в том, что в нем нет элементов, которые фактически требуют его выравнивания по границе слова (например, целое число). Например, если вы разместите char x; int y; внутри класса мой GCC синхронизирует его с восемью байтами (так как второй int должен быть выровнен в этом реализация.)

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

Здравствуйте, VNG, Вы писали:

VNG>Так вот. Получается, что sizeof(CPtr1<int>) == 8, а sizeof(CPtr2<int>) == 4.
VNG>Корректно ли это (компилятор MSVC++ 7.1)? И как это коррелирует со стандартом?
Читайте сюда:

В связи с тем, что методы можно объявлять внутри класса, нужно разобраться, влияет ли размер метода на размер класса в памяти? И сколько байт выделяет компилятор для класса и для структуры — одинаковы ли эти значения? Как обычно, это можно сделать с помощью функции sizeof(тип). Интересно также выяснить, выделяется ли память для "пустых" классов, не содержащих ни полей, ни методов. Напишем простую программу, текст которой приведен в листинге 1.23.

Вывод этой программы в системах Visual C++ выглядит так:


Так как мы не меняли никаких режимов трансляции, это означает, что в отладочном режиме по умолчанию компилятор работает так:
1. Для класса и структуры память выделяется совершенно одинаково.
2. Даже "пустой" класс занимает в памяти некоторой количество байтов; в данном случае — один.
3. Если в классе объявлено только одно поле, то памяти выделяется ровно столько, сколько занимает значение соответствующего типа в памяти.
4. В системах Visual C++ размеры типов double и long double равны 8.
5. Если в классе несколько полей, то выделяется количество памяти, кратное наибольшему размеру.
6. Метод в классе места не занимает.
Те же самые числа выдаются и в режиме трансляции Release. Однако при запуске той же программы в системе Borland C++ Builder 6 на экран выводятся другие значения:


Как видите, в этом случае выделяется ровно столько памяти, сколько занимают соответствующие типы. По-прежнему для пустого класса выделяется 1 байт, а размер long double равен 8, что совпадает с размером "простого" double.
Вывод программы в системе Borland C++ Builder 6


отличается только тем, что для типа long double выделяется 10 байт, а не 8, как для типа double. Это в точности соответствует размерам аппаратного типа в компьютере.
Интерес представляет также использование "пустого" класса в качестве поля другого класса. Добавим в нашу программу следующие строки:


Это означает, что каждое "пустое" поле добавляет в класс 1 байт. В системе C++ Builder получаем несколько другой результат:


Это означает, что в этой системе в отладочном режиме по умолчанию "пустое" поле не занимает место в классе. Однако можно установить режим трансляции, при котором "пустые" поля будут вести себя точно так же, как в Visual C++.
При "выключении" выравнивания ситуация по умолчанию остается аналогичной. В системе Visual C++ получаем на экране


А C++ Builder выдает
[ccode]
Empty in
class 8; structure 8
class 8; structure 8
class 8; structure 8
class 8; structure 8
[ccode]

Таким образом, и в этом случае система по умолчанию не тратит место на "пустые" поля.

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

Установка

Откройте профилировщик производительности (ALT+F2) в Visual Studio.

Выбранное средство отслеживания выделения объектов Dotnet

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

Окно с параметром Остановить сбор

Щелкните вкладку Выделение. Теперь содержимое окна должно выглядеть как на снимке экрана ниже.

Вкладка Выделение

Теперь вы можете проанализировать выделение памяти объектам.

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

Параметры для средства выделения Dotnet

Настройте необходимую частоту выборки. Такое изменение улучшит производительность приложения во время сбора и анализа.

Настройка частоты выборки

Дополнительные сведения о том, как сделать средство более эффективным, см. в статье Оптимизация параметров профилировщика.

Анализ данных

Граф для средства выделения Dotnet

В предыдущем графическом представлении на верхнем графе показано количество активных объектов в приложении. На нижнем графе Object delta (Изменение объекта) показано процентное изменение объектов приложения. Красные столбцы обозначают, что была проведена сборка мусора.

Отфильтрованный граф по времени выделения Dotnet

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

Выделение

Развернутое представление Выделение

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

Столбец Тип содержит список классов и структур, занимающих память. Дважды щелкните тип, чтобы просмотреть его обратную трассировку в виде инвертированного дерева вызовов. Только в представлении Выделение можно просмотреть элементы в выбранной категории, занимающей память.

В столбце Выделения показано количество занимающих память объектов, относящихся к определенному типу выделения или функции. Этот столбец отображается только в представлениях Выделение, Дерево вызовов и Функции.

Столбцы Байты и Средний размер (байты) по умолчанию скрыты. Чтобы их отобразить, щелкните правой кнопкой мыши столбец Тип или Выделения, а затем выберите параметры Байты и Средний размер (байты) , чтобы добавить их в диаграмму.

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

В столбце Имя модуля показан модуль, содержащий вызывающую функцию или процесс.

Все эти столбцы можно сортировать. Для столбцов Тип и Имя модуля можно сортировать элементы в алфавитном порядке по возрастанию или убыванию. Для столбцов Выделения, Байты и Средний размер (байт) можно сортировать элементы по увеличению или уменьшению числовых значений.

Символы

На вкладках Выделение, Дерево вызовов и Функции отображаются следующие символы:

— тип значения, например целое число.

— коллекция типа значения, например массив целых чисел.

— ссылочный тип, например строка.

— коллекция ссылочного типа, например массив строк.

Дерево вызовов

Представление Дерево вызовов

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

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

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

В столбцах Self (Allocations) (Собственные (выделения)) и Self-Size (Bytes) (Собственный размер (байт)) отображается количество выделенных объектов и объем памяти, используемый одной выбранной функцией или типом выделения.

В столбце Average Size (Bytes) (Средний размер (байт)) отображаются те же сведения, что и в представлении Выделения.

В столбце Имя модуля показан модуль, содержащий вызывающую функцию или процесс.

Развернутый критический путь

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

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

Функции

Представление Функции

В представлении Функции показаны процессы, модули и функции, для которых выделяется память.

В столбце Имя отображаются процессы в качестве узлов верхнего уровня. Под процессами располагаются модули, а под ними — функции.

В этих столбцах приводятся те же сведения, что и в представлениях Выделение и Дерево вызовов:

  • Total (Allocations) (Всего (выделения));
  • Self (Allocations) (Собственные (выделения));
  • Общий размер (байт) ;
  • Self-Size (Bytes) (Собственный размер (байт));
  • Average Size (Bytes) (Средний размер (байт)).

Collection

Представление Коллекция

В представлении Коллекция показано, сколько объектов было собрано или осталось во время сборки мусора. В нем также имеются круговые диаграммы для визуализации собранных и сохранившихся объектов по типу.

  • В столбце Собрано показано количество объектов, собранных сборщиком мусора.
  • В столбце Осталось показано количество объектов, сохранившихся после работы сборщика мусора.

Средства фильтрации

В каждом из представлений Выделения, Дерево вызовов и Функции есть параметры Показать только мой код и Show Native Code (Показать машинный код), а также поле фильтра.

Читайте также: