Размер байта в памяти - Java - PullRequest
50 голосов
/ 23 октября 2008

Я слышал неоднозначное мнение об объеме памяти, занимаемой байтом в Java-программе.

Я знаю, что вы можете хранить не более +127 в байте Java, а в документации говорится, что байт только 8 бит, но здесь Мне сказали, что это на самом деле занимает тот же объем памяти, что и int, и, следовательно, является просто типом, который помогает в понимании кода, а не в эффективности.

Может кто-нибудь прояснить это, и будет ли это проблемой, специфичной для реализации?

Ответы [ 13 ]

60 голосов
/ 23 октября 2008

Хорошо, было много дискуссий и не так много кода:)

Вот быстрый тест. Когда дело доходит до такого рода вещей, у него есть обычные предостережения - у тестирования памяти есть странности из-за JITting и т. Д., Но с достаточно большими числами это полезно в любом случае. Он имеет два типа, каждый с 80 членами - LotsOfBytes имеет 80 байтов, LotsOfInts имеет 80 дюймов. Мы создаем много из них, проверяем, что они не GC'd, и проверяем использование памяти:

class LotsOfBytes
{
    byte a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af;
    byte b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf;
    byte c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf;
    byte d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, da, db, dc, dd, de, df;
    byte e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, ea, eb, ec, ed, ee, ef;
}

class LotsOfInts
{
    int a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, aa, ab, ac, ad, ae, af;
    int b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf;
    int c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, ca, cb, cc, cd, ce, cf;
    int d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, da, db, dc, dd, de, df;
    int e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, ea, eb, ec, ed, ee, ef;
}


public class Test
{
    private static final int SIZE = 1000000;

    public static void main(String[] args) throws Exception
    {        
        LotsOfBytes[] first = new LotsOfBytes[SIZE];
        LotsOfInts[] second = new LotsOfInts[SIZE];

        System.gc();
        long startMem = getMemory();

        for (int i=0; i < SIZE; i++)
        {
            first[i] = new LotsOfBytes();
        }

        System.gc();
        long endMem = getMemory();

        System.out.println ("Size for LotsOfBytes: " + (endMem-startMem));
        System.out.println ("Average size: " + ((endMem-startMem) / ((double)SIZE)));

        System.gc();
        startMem = getMemory();
        for (int i=0; i < SIZE; i++)
        {
            second[i] = new LotsOfInts();
        }
        System.gc();
        endMem = getMemory();

        System.out.println ("Size for LotsOfInts: " + (endMem-startMem));
        System.out.println ("Average size: " + ((endMem-startMem) / ((double)SIZE)));

        // Make sure nothing gets collected
        long total = 0;
        for (int i=0; i < SIZE; i++)
        {
            total += first[i].a0 + second[i].a0;
        }
        System.out.println(total);
    }

    private static long getMemory()
    {
        Runtime runtime = Runtime.getRuntime();
        return runtime.totalMemory() - runtime.freeMemory();
    }
}

Вывод на мой ящик:

Size for LotsOfBytes: 88811688
Average size: 88.811688
Size for LotsOfInts: 327076360
Average size: 327.07636
0

Так что, очевидно, есть некоторые издержки - 8 байтов, по всей видимости, хотя почему-то только 7 для LotsOfInts (как я уже сказал, здесь есть странности), но дело в том, что байтовые поля упакованы для LotsOfBytes так что он (после удаления служебных данных) занимает всего четверть памяти, чем LotsOfInts.

18 голосов
/ 23 октября 2008

Да, байтовая переменная в Java на самом деле занимает 4 байта в памяти. Однако это не относится к массивам. Хранение байтового массива из 20 байтов фактически составляет всего 20 байтов в памяти.

Это потому, что язык байт-кода Java знает только два типа целых чисел: целые и длинные. Поэтому он должен обрабатывать все числа внутри каждого типа, и эти типы имеют 4 и 8 байтов в памяти.

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

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

7 голосов
/ 23 октября 2008

Java никогда не зависит от реализации или платформы (по крайней мере, что касается размеров примитивных типов ). Эти примитивные типы всегда гарантированно остаются неизменными независимо от того, на какой платформе вы находитесь. Это отличается от (и считалось улучшением) C и C ++, где некоторые из примитивных типов зависели от платформы.

Поскольку базовая операционная система быстрее обращается к четырем (или восьми, в 64-битной системе) байтам одновременно, JVM может выделять больше байтов для хранения примитивного байта, но вы все равно можете хранить значения только из От -128 до 127 в нем.

5 голосов
/ 16 декабря 2012

Я сделал тест, используя http://code.google.com/p/memory-measurer/ Обратите внимание, что я использую 64-битную Oracle / Sun Java 6 без сжатия ссылок и т. Д.

Каждый объект занимает некоторое пространство, плюс JVM должен знать адрес этого объекта, а сам «адрес» составляет 8 байтов.

С примитивами похоже, что примитивы приводятся к 64-битной для лучшей производительности (конечно!):

byte: 16 bytes,
 int: 16 bytes,
long: 24 bytes.

С массивами:

byte[1]: 24 bytes
 int[1]: 24 bytes
long[1]: 24 bytes

byte[2]: 24 bytes
 int[2]: 24 bytes
long[2]: 32 bytes

byte[4]: 24 bytes
 int[4]: 32 bytes
long[4]: 48 bytes

byte[8]: 24 bytes => 8 bytes, "start" address, "end" address => 8 + 8 + 8 bytes
 int[8]: 48 bytes => 8 integers (4 bytes each), "start" address, "end" address => 8*4 + 8 + 8 bytes
long[8]: 80 bytes => 8 longs (8 bytes each), "start" address, "end" address => 8x8 + 8 + 8 bytes

А теперь угадайте, что ...

    byte[8]: 24 bytes
 byte[1][8]: 48 bytes
   byte[64]: 80 bytes
 byte[8][8]: 240 bytes

P.S. Oracle Java 6, последняя и лучшая, 64-разрядная, 1.6.0_37, MacOS X

5 голосов
/ 23 октября 2008

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

Обратите внимание, что массивы байтов не хранятся в виде массивов 4-байтовых значений, поэтому байтовый массив длиной 1024 будет использовать 1 КБ памяти (игнорируя любые издержки).

3 голосов
/ 23 октября 2008

Это зависит от того, как JVM применяет заполнение и т. Д. Массив байтов (в любой разумной системе) будет упакован в 1 байт на элемент, но класс с четырьмя байтовыми полями может быть либо плотно упакован, либо дополнен границы слова - это зависит от реализации.

2 голосов
/ 27 октября 2008

байт = 8 бит = один байт, определенный в спецификации Java.

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

Для Sun JVM я задокументировал правила: https://www.sdn.sap.com/irj/sdn/weblogs?blog=/pub/wlg/5163

2 голосов
/ 23 октября 2008

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

2 голосов
/ 23 октября 2008

То, что вам сказали, совершенно верно. Спецификация байтового кода Java имеет только 4-байтовые типы и 8-байтовые типы.

byte, char, int, short, boolean, float хранятся в 4 байтах каждый.

double и long хранятся в 8 байтах.

Однако байт-код - это только половина истории. Есть также JVM, которая зависит от реализации. В байт-коде Java достаточно информации, чтобы определить, что переменная была объявлена ​​как байт. Разработчик JVM может решить использовать только байт, хотя я думаю, что это крайне маловероятно.

0 голосов
/ 09 августа 2012

Просто хотел отметить, что утверждение

Вы можете хранить не более +127 в байте Java

не совсем правильно.

Вы всегда можете хранить 256 различных значений в байте, поэтому вы можете легко иметь диапазон 0..255, как если бы он был «беззнаковым» байтом.

Все зависит от того, как вы обрабатываете эти 8 битов.

Пример:

byte B=(byte)200;//B contains 200
System.out.println((B+256)%256);//Prints 200
System.out.println(B&0xFF);//Prints 200
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...