Tamaño de un byte en la memoria – Java

He escuchado opiniones encontradas sobre la cantidad de memoria que ocupa un byte en un progtwig Java.

Soy consciente de que no puedes almacenar más de +127 en un byte de Java, y la documentación dice que un byte es de solo 8 bits, pero aquí me dicen que en realidad ocupa la misma cantidad de memoria que un int, y por lo tanto es solo un Tipo que ayuda a la comprensión del código y no a la eficiencia.

¿Alguien puede aclarar esto y sería un problema específico de la implementación?

De acuerdo, ha habido mucha discusión y no mucho código 🙂

Aquí hay un punto de referencia rápido. Tiene las salvedades normales cuando se trata de este tipo de cosas: la memoria de prueba tiene rarezas debido a JITting, etc., pero con números adecuadamente grandes es útil de todos modos. Tiene dos tipos, cada uno con 80 miembros: LotsOfBytes tiene 80 bytes, LotsOfInts tiene 80 ints. Construimos muchos de ellos, nos aseguramos de que no tengan GC, y controlamos el uso de la memoria:

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(); } } 

Salida en mi caja:

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

Así que obviamente hay algo de sobrecarga - 8 bytes por apariencia, aunque de alguna manera solo 7 para LotsOfInts (como dije, hay rarezas aquí), pero el punto es que los campos de bytes parecen estar empaquetados para LotsOfBytes de modo que toma (después de la eliminación de sobrecarga) solo una cuarta parte de memoria que LotsOfInts.

Sí, una variable de bytes es, de hecho, 4 bytes en la memoria. Sin embargo, esto no es cierto para las matrices. Una matriz de bytes de 20 bytes es, de hecho, solo 20 bytes en la memoria. Esto se debe a que Java Bytecode Language solo conoce ints y longs como tipos de número (por lo que debe manejar todos los números como cualquier tipo de ambos, 4 bytes u 8 bytes), pero conoce matrices con cualquier tamaño de número posible (por lo que las matrices cortas De hecho, dos bytes por entrada y matrices de bytes son, de hecho, un byte por entrada.

Java nunca es una implementación o plataforma específica (al menos en lo que respecta a los tamaños de tipo primitivos ). Siempre se garantiza que los tipos primitivos seguirán siendo los mismos independientemente de la plataforma en la que se encuentre. Esto difiere de (y se consideró una mejora en) C y C ++, donde algunos de los tipos primitivos eran específicos de la plataforma.

Dado que es más rápido para el sistema operativo subyacente abordar cuatro (u ocho, en un sistema de 64 bits) bytes a la vez, la JVM puede asignar más bytes para almacenar un byte primitivo, pero solo puede almacenar valores de -128 a 127 en eso.

Un ejercicio revelador es ejecutar javap en algún código que hace cosas simples con bytes y entradas. Verá bytecodes que esperan que los parámetros int operen en bytes y que se inserten bytecodes para co-ercer de uno a otro.

Sin embargo, tenga en cuenta que las matrices de bytes no se almacenan como matrices de valores de 4 bytes, por lo que una matriz de bytes de 1024 de longitud utilizará 1k de memoria (ignorando los gastos generales).

Hice una prueba usando http://code.google.com/p/memory-measurer/ Tenga en cuenta que estoy usando Oracle / Sun Java 6 de 64 bits, sin ninguna compresión de referencias, etc.

Cada objeto ocupa un espacio, además de que JVM necesita saber la dirección de ese objeto, y la “dirección” en sí misma tiene 8 bytes.

Con primitivos, parece que las primitivas están fundidas a 64 bits para un mejor rendimiento (¡por supuesto!):

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

Con matrices:

 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 

Y ahora adivina qué …

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

PS Oracle Java 6, último y mejor, 64 bits, 1.6.0_37, MacOS X

Depende de cómo la JVM aplica relleno, etc. Un conjunto de bytes (en cualquier sistema en su sano juicio) se empaquetará en 1 byte por elemento, pero una clase con cuatro campos de bytes podría estar bien empaquetada o acolchada en los límites de las palabras. depende de la implementación.

Lo que le han dicho es exactamente correcto. La especificación del código de bytes Java solo tiene tipos de 4 bytes y tipos de 8 bytes.

byte, char, int, short, boolean, float se almacenan en 4 bytes cada uno.

doble y largo se almacenan en 8 bytes.

Sin embargo, el código de bytes es solo la mitad de la historia. También está la JVM, que es específica de la implementación. Hay suficiente información en el código de bytes Java para determinar que una variable fue declarada como un byte. Un implementador de JVM puede decidir usar solo un byte, aunque creo que es muy poco probable.

Siempre puedes usar largos y empacar los datos en ti para boost la eficiencia. Entonces siempre puedes asegurarte de que usarás los 4 bytes.

byte = 8bit = un byte definido por la especificación Java.

cuánta memoria necesita una matriz de bytes no está definida por la especificación, ni se define cuánto necesita un objeto complejo.

Para Sun JVM documenté las reglas: https://www.sdn.sap.com/irj/sdn/weblogs?blog=/pub/wlg/5163

Ver mis herramientas de monitoreo en mi sitio (www.csd.uoc.gr/~andreou)

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

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

(También puede usarse para objetos más complejos / gráficos de objetos)

En el 1.6 JDK de Sun, parece que un byte realmente toma un solo byte (en versiones anteriores, int ~ byte en términos de memoria). Pero tenga en cuenta que incluso en versiones anteriores, byte [] también se empaquetaba en un byte por entrada.

De todos modos, el punto es que no hay necesidad de pruebas complejas como la anterior de Jon Skeet, que solo dan estimaciones. ¡Podemos medir directamente el tamaño de un objeto!

Al leer los comentarios anteriores, parece que mi conclusión será una sorpresa para muchos (también es una sorpresa para mí), por lo que vale la pena repetir:

  • El antiguo tamaño (int) == tamaño (byte) para variables no tiene más , al menos en Java 6 de Sun.

En cambio, tamaño (byte) == 1 byte (!!)

Solo quería señalar que la statement

no puedes almacenar más de +127 en un byte de java

no es realmente correcto

Siempre puede almacenar 256 valores diferentes en un byte, por lo tanto, puede tener fácilmente su rango 0..255 como si fuera un byte “sin signo”.

Todo depende de cómo manejes esos 8 bits.

Ejemplo:

 byte B=(byte)200;//B contains 200 System.out.println((B+256)%256);//Prints 200 System.out.println(B&0xFF);//Prints 200 

Parece que la respuesta probablemente dependa de su versión de JVM y probablemente también de la architecture de la CPU en la que esté ejecutando. La línea de CPU Intel hace una manipulación de bytes eficiente (debido a su historial de CPU de 8 bits). Algunos chips RISC requieren alineación de palabra (4 bytes) para muchas operaciones. Y la asignación de memoria puede ser diferente para las variables en la stack, los campos en una clase y en una matriz.