Вы можете предположить, что уменьшение размера структуры или класса экономит тот же объем памяти. Однако из-за выравнивания памяти в распределителях памяти это может не иметь никакого значения или, возможно, большего, чем вы могли бы ожидать. Это потому, что объем зарезервированной памяти обычно кратен выравниванию памяти. Для Java и C это может 8 или 16 байтов.
Размер памяти зарезервирован
Эти тесты были выполнены в 64-битной программе на C (gcc 4.5.2) и 64 JVM (Oracle Java 7). В Java прямая память в значительной степени является оболочкой для malloc и свободной.
Б | C malloc () зарезервировано | Java ByteBuffer.allocateDirect () |
---|---|---|
От 0 до 24 | 32 байта | 32 байта + байтовый буфер |
От 25 до 40 | 48 байтов | 48 байт + байтовый буфер |
С 41 по 56 | 64 байта | 64 байта + байтовый буфер |
57 до 72 | 80 байт | 80 байт + байтовый буфер |
Построение объектов — похожая история
Количество полей | Класс C int (куча / стек) |
Класс C void * (куча / стек) |
Класс Java с int |
Java-класс с объектными ссылками |
---|---|---|---|---|
1 | 32/16 байт | 32/16 байт | 16 байт | 16 байт |
2 | 32/16 байт | 32/16 байт | 24 байта | 24 байта |
3 | 32/16 байт | 32/32 байта | 24 байта | 24 байта |
4 | 32/16 байт | 48/32 байта | 32 байта | 32 байта |
5 | 32/32 байта | 48/48 байт | 32 байта | 32 байта |
6 | 32/32 байта | 64/48 байт | 40 байт | 40 байт |
7 | 48/32 байта | 64/64 байта | 40 байт | 40 байт |
8 | 48/32 байта | 80/64 байта | 48 байтов | 48 байтов |
Использование структуры / класса C в стеке более эффективно, чем другие подходы, по ряду причин, две из которых заключаются в том, что нет заголовка управления памятью и нет дополнительного указателя / ссылки (не показано в таблице).
JVM Sun / Oracle и OpenJDK 6 и 7 будут использовать 32-разрядные ссылки и 8-байтовую память, выровненную для поддержки до 32 ГБ (8 * 4 Г). Большинство JVM имеют размер менее 32 ГБ, что делает эту полезную оптимизацию. Примечание. Одной из причин того, что JVM обычно имеют размер от 1 до 4 ГБ, является то, что в худшем случае время полного GC обычно составляет 1 секунду на ГБ кучи, а время полного CG 30 секунд слишком велико для большинства приложений. Типичный способ обойти эту проблему полного времени GC — сохранить рабочий размер кучи до нескольких ГБ и использовать внешнюю базу данных или память без кучи «direct» и «memory mapped».
Другое решение для Java — использовать параллельный коллектор без пауз, такой как предоставляемый Azul. Они заявляют о превосходной масштабируемости за пределами 40 ГБ кучи, но открыто не перечисляют свои затраты;)
Почему это важно?
Скажем, у вас есть такой класс
class MyClass { int num; short value; }
В C, сколько памяти экономится путем изменения num на short или сколько больше потребляется с этим делает long long . Скорее всего, ответ будет нулевым (если у вас нет такого массива). В Java это может иметь значение, так как размер выравнивания отличается. И наоборот, если класс / структура C имеет размер 16 или 17 байтов, он может сделать размер в стеке 16 или 32 байта. Точно так же, будучи 24 или 25 байтами, можно сделать размер используемого malloc 32 или 48 байтов.
Код
MemoryAlignment / main.cpp и
MemoryAlignment.java
От http://vanillajava.blogspot.com/2011/09/memory-alignment-in-cc-and-java.html