2008-10-23 3 views
48

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

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

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

+0

Один байт занимает 4/8 байт в зависимости от архитектуры процессора, байт в байте [] принимает ровно один байт + заголовок объекта (+ trailing align) – bestsss 2011-02-05 09:58:35

+1

"* Я знаю, что вы можете хранить не более +127 в байте java *" - Не верно, в некотором смысле. Вы можете хранить 256 различных значений в байте, поэтому вы можете ** хранить в нем более 127 в нем: до 255, если вы начинаете с 0. Все зависит от того, как вы обрабатываете эти 8 бит. Только для педантизма: P – 2012-08-08 14:05:25

ответ

59

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

Вот быстрый тест.У этого есть нормальные оговорки, когда дело доходит до такого рода вещи - тестирование памяти имеет странности из-за 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.

7

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

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

+1

Даже если он использует 4 байта для хранения байта, массив байтов, вероятно, будет упакован. Я был бы удивлен, если бы байт [4] использовал 16 байтов вместо 4 байтов. – Kip 2008-10-23 14:32:21

+1

Возможно. Это * будет * специфичным для реализации. Я честно не знаю, какой метод будет быстрее. – 2008-10-23 14:36:05

+1

статья верна, но комментарий неправильный. одна байтовая переменная потребляет 1 байт + aligment. 8 байтовых переменных на Sun JVM, например, стоят 8 байтов – kohlerm 2008-10-27 20:40:43

2

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

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

двойной и длинный хранятся в 8 байтах.

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

+0

Хм ... это похоже на http://java.sun.com/docs/books/jvms/second_edition/html/Overview.doc.html#31446: «Значения интегральных типов виртуальной машины Java такие же, как и для интегральных типов языка программирования Java (§2.4.1)» (Ищете сейчас байт-код) – 2008-10-23 14:24:48

+0

Есть что-то: http://java.sun.com/docs/books/jvms/second_edition/html/Overview.doc.html#7565 - bipush, baload и bastore работают на байтовый тип ... * арифметика * выполняется только на ints/longs , но это другое дело. – 2008-10-23 14:26:00

+0

Джон, я описал спецификацию байтового кода. Это отличается от спецификации JVM. – 2008-10-23 14:27:09

3

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

2

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

5

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

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

14

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

2

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

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

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

0

увидеть мои MonitoringTools на моем сайте (www.csd.uoc.gr/~andreou)

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

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

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

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

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

0

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

  • старый размер (целое) == размер (байт) для переменных не имеет не более, по крайней мере, в Java компании Sun 6.

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

-3

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

0

Просто хотелось бы отметить, что заявление

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

Я сделал тест с помощью 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 

PS Oracle Java 6, последний и самый большой, 64-разрядный, 1.6.0_37, MacOS X

Смежные вопросы