Размер байт в памяти - Java

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

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

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

Ответ 1

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

Вот быстрый тест. Он получил нормальные оговорки, когда дело доходит до такого рода вещей - тестирование памяти имеет странности из-за JITting и т.д., Но с подходящими большими числами это полезно в любом случае. Он имеет два типа: каждый из 80 членов - LotsOfBytes имеет 80 байт, LotsOfInts имеет 80 ints. Мы создаем много из них, убедитесь, что они не 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.

Ответ 2

Да, байтовая переменная на самом деле составляет 4 байта в памяти. Однако это не относится к массивам. Байт-массив из 20 байтов на самом деле составляет всего 20 байт в памяти. Это связано с тем, что язык байт-кода Java знает только числа ints и longs как типы номеров (поэтому он должен обрабатывать все числа как один из двух, 4 байта или 8 байтов), но он знает массивы с любым возможным размером числа (поэтому короткие массивы находятся в факт, что два байта на запись и байт-массивы фактически являются одним байтом для каждой записи).

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

Я сделал тест, используя 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

Ответ 6

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

Ответ 7

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

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

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

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

Ответ 8

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

Ответ 9

byte = 8bit = один байт, определенный Java Spec.

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

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

Ответ 10

См. мои объекты мониторинга на моем сайте (www.csd.uoc.gr/~andreou)

class X {
   byte b1, b2, b3...;
}

long memoryUsed = MemoryMeasurer.measure(new X());

(Он может использоваться и для более сложных объектов/графов объектов)

В Sun 1.6 JDK кажется, что байт действительно принимает один байт (в более старых версиях, int ~ byte в терминах памяти). Но обратите внимание, что даже в более старых версиях байт [] также был упакован в один байт на запись.

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

Ответ 11

Прочитав вышеприведенные комментарии, кажется, что мой вывод станет для многих неожиданностью (это тоже неожиданно для меня), поэтому стоит повторить:

  • Размер старого (int) == size (byte) для переменных не превышает, по крайней мере, в Sun Java 6.

Вместо этого размер (байт) == 1 байт (!!)

Ответ 12

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

вы можете сохранить не более +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

Ответ 13

Похоже, что ответ, вероятно, будет зависеть от вашей версии JVM и, возможно, также от архитектуры процессора, на которой вы работаете. Линейка процессоров Intel эффективно выполняет байтовую манипуляцию (из-за 8-разрядной истории процессора). Для некоторых RISC-чипов для много операций требуется выравнивание по словам (4 байта). И распределение памяти может быть различным для переменных в стеке, полей в классе и в массиве.