tipos - que es un objeto en java
¿Cuál es el consumo de memoria de un objeto en Java? (12)
¿El espacio de memoria consumido por un objeto con 100 atributos es el mismo que el de 100 objetos, con un atributo cada uno?
¿Cuánta memoria se asigna a un objeto?
¿Cuánto espacio adicional se usa al agregar un atributo?
¿El espacio de memoria consumido por un objeto con 100 atributos es el mismo que el de 100 objetos, con un atributo cada uno?
No.
¿Cuánta memoria se asigna a un objeto?
- La sobrecarga es de 8 bytes en 32 bits, 12 bytes en 64 bits; y luego redondeado a un múltiplo de 4 bytes (32 bits) u 8 bytes (64 bits).
¿Cuánto espacio adicional se usa al agregar un atributo?
- Los atributos van desde 1 byte (char / boolean) a 8 bytes (long / double), pero las referencias son de 4 bytes u 8 bytes dependiendo de si es de 32 bits o de 64 bits, sino de si -Xmx es <32Gb o> = 32Gb: Las JVM típicas de 64 bits tienen una optimización llamada "-UseCompressedOops" que comprime las referencias a 4 bytes si el montón está por debajo de 32Gb.
Cada objeto tiene una cierta sobrecarga para su monitor asociado y la información de tipo, así como los propios campos. Más allá de eso, los campos pueden ser distribuidos en gran medida, sin embargo, la JVM lo considera conveniente (creo), pero como se muestra en otra respuesta , al menos algunas JVM se empaquetarán con bastante fuerza. Considera una clase como esta:
public class SingleByte
{
private byte b;
}
vs
public class OneHundredBytes
{
private byte b00, b01, ..., b99;
}
En una JVM de 32 bits, esperaría que 100 instancias de SingleByte
tomen 1200 bytes (8 bytes de sobrecarga + 4 bytes para el campo debido al relleno / alineación). Yo esperaría que una instancia de OneHundredBytes
tomara 108 bytes: la sobrecarga, y luego 100 bytes, empaquetados. Sin embargo, puede variar según la JVM: una implementación puede decidir no empaquetar los campos en OneHundredBytes
, lo que lleva a tomar 408 bytes (= 8 bytes de sobrecarga + 4 * 100 bytes alineados / rellenados). En una JVM de 64 bits, la sobrecarga también puede ser más grande (no estoy seguro).
EDITAR: ver el comentario a continuación; Aparentemente, los pads HotSpot SingleByte
límites de 8 bytes en lugar de 32, por lo que cada instancia de SingleByte
tomaría 16 bytes.
De cualquier manera, el "objeto grande único" será al menos tan eficiente como los objetos pequeños múltiples, para casos simples como este.
Depende de la arquitectura / jdk. Para una arquitectura moderna de JDK y 64 bits, un objeto tiene un encabezado de 12 bytes y un relleno de 8 bytes, por lo que el tamaño mínimo del objeto es de 16 bytes. Puede usar una herramienta llamada Java Object Layout para determinar un tamaño y obtener detalles sobre el diseño de objetos y la estructura interna de cualquier entidad o adivinar esta información por referencia de clase. Ejemplo de una salida para Integer en mi entorno:
Running 64-bit HotSpot VM.
Using compressed oop with 3-bit shift.
Using compressed klass with 3-bit shift.
Objects are 8 bytes aligned.
Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
java.lang.Integer object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 12 (object header) N/A
12 4 int Integer.value N/A
Instance size: 16 bytes (estimated, the sample instance is not available)
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
Entonces, para Integer, el tamaño de la instancia es de 16 bytes, debido a que se compacta la ubicación de 4 bytes justo después del encabezado y antes de rellenar el límite.
Ejemplo de código:
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.util.VMSupport;
public static void main(String[] args) {
System.out.println(VMSupport.vmDetails());
System.out.println(ClassLayout.parseClass(Integer.class).toPrintable());
}
Si usas maven, para obtener JOL:
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.3.2</version>
</dependency>
El total de la memoria utilizada / libre de un programa se puede obtener en el programa a través de
java.lang.Runtime.getRuntime();
El tiempo de ejecución tiene varios métodos que se relacionan con la memoria. El siguiente ejemplo de codificación demuestra su uso.
package test;
import java.util.ArrayList;
import java.util.List;
public class PerformanceTest {
private static final long MEGABYTE = 1024L * 1024L;
public static long bytesToMegabytes(long bytes) {
return bytes / MEGABYTE;
}
public static void main(String[] args) {
// I assume you will know how to create a object Person yourself...
List < Person > list = new ArrayList < Person > ();
for (int i = 0; i <= 100000; i++) {
list.add(new Person("Jim", "Knopf"));
}
// Get the Java runtime
Runtime runtime = Runtime.getRuntime();
// Run the garbage collector
runtime.gc();
// Calculate the used memory
long memory = runtime.totalMemory() - runtime.freeMemory();
System.out.println("Used memory is bytes: " + memory);
System.out.println("Used memory is megabytes: " + bytesToMegabytes(memory));
}
}
En caso de que sea útil para cualquiera, puede descargar desde mi sitio web un pequeño agente de Java para consultar el uso de memoria de un objeto . También te permitirá consultar el uso "profundo" de la memoria.
He obtenido muy buenos resultados con el enfoque java.lang.instrument.Instrumentation mencionado en otra respuesta. Para obtener buenos ejemplos de su uso, consulte la entrada, Contador de memoria de instrumentación del boletín de JavaSpecialists ''y la biblioteca java.sizeOf en SourceForge.
La pregunta será muy amplia.
Depende de la variable de clase o puede llamar como uso de memoria de estados en java.
También tiene algún requisito de memoria adicional para encabezados y referencias.
La memoria de pila utilizada por un objeto Java incluye
memoria para campos primitivos, de acuerdo con su tamaño (ver más abajo para Tamaños de tipos primitivos);
memoria para campos de referencia (4 bytes cada uno);
un encabezado de objeto, que consta de unos pocos bytes de información de "mantenimiento";
Los objetos en Java también requieren cierta información de "mantenimiento", como la grabación de la clase de un objeto, la identificación y las banderas de estado, como si el objeto está actualmente accesible, la sincronización está bloqueada, etc.
El tamaño del encabezado del objeto Java varía en 32 y 64 bits jvm.
Aunque estos son los principales consumidores de memoria, jvm también requiere campos adicionales, como la alineación del código, etc.
Tamaños de tipos primitivos.
booleano y byte - 1
char & short - 2
int & float - 4
largo y doble - 8
Las reglas sobre cuánta memoria se consume dependen de la implementación de JVM y la arquitectura de la CPU (por ejemplo, 32 bits frente a 64 bits).
Para las reglas detalladas para la JVM de SUN, consulte mi blog anterior
Saludos, Markus
No, registrar un objeto también requiere un poco de memoria. 100 objetos con 1 atributo ocuparán más memoria.
Parece que cada objeto tiene una sobrecarga de 16 bytes en sistemas de 32 bits (y 24 bytes en sistemas de 64 bits).
http://algs4.cs.princeton.edu/14analysis/ es una buena fuente de información. Un ejemplo entre muchos buenos es el siguiente.
cs.virginia.edu/kim/publicity/pldi09tutorials/… también es muy informativo, por ejemplo:
no, 100 objetos pequeños necesitan más información (memoria) que uno grande.
Mindprod señala que esta no es una pregunta directa para responder:
Una JVM es libre de almacenar datos de cualquier manera que le guste internamente, sea grande o pequeña, con cualquier cantidad de relleno o sobrecarga, aunque los primitivos deben comportarse como si tuvieran los tamaños oficiales.
Por ejemplo, la JVM o el compilador nativo puede decidir almacenar unboolean[]
en fragmentos de 64 bits como unBitSet
. No tiene que decirle, siempre y cuando el programa dé las mismas respuestas.
- Podría asignar algunos objetos temporales en la pila.
- Puede optimizar algunas variables o llamadas a métodos totalmente fuera de existencia reemplazándolas con constantes.
- Es posible que la versión de los métodos o bucles, es decir, compilar dos versiones de un método, cada uno optimizado para una determinada situación, y luego decidir cuál de ellos llamar por adelantado.
Luego, por supuesto, el hardware y el sistema operativo tienen cachés multicapa, en caché de chip, caché SRAM, caché DRAM, conjunto de trabajo de RAM ordinaria y almacén de respaldo en el disco. Sus datos pueden estar duplicados en cada nivel de caché. Toda esta complejidad significa que solo se puede predecir de forma aproximada el consumo de RAM.
Metodos de medicion
Puede usar Instrumentation.getObjectSize()
para obtener una estimación del almacenamiento consumido por un objeto.
Para visualizar el diseño real del objeto, la huella y las referencias, puede utilizar la herramienta JOL (Diseño de objeto Java) .
Encabezados de objetos y referencias de objetos
En un JDK moderno de 64 bits, un objeto tiene un encabezado de 12 bytes, rellenado a un múltiplo de 8 bytes, por lo que el tamaño mínimo del objeto es de 16 bytes. Para JVM de 32 bits, la sobrecarga es de 8 bytes, rellenada a un múltiplo de 4 bytes. (De la respuesta de Dmitry Spikhalskiy, la respuesta de Jayen y JavaWorld ).
Normalmente, las referencias son de 4 bytes en plataformas de 32 bits o en plataformas de 64 bits hasta -Xmx32G
; y 8 bytes por encima de 32Gb ( -Xmx32G
). (Ver referencias de objetos comprimidos ).
Como resultado, una JVM de 64 bits normalmente requeriría un 30-50% más de espacio de almacenamiento dinámico. ( ¿Debo usar una JVM de 32 o de 64 bits?, 2012, JDK 1.7)
Tipos de caja, matrices y cadenas
Los envoltorios en caja tienen una sobrecarga en comparación con los tipos primitivos (de JavaWorld ):
Integer
: el resultado de 16 bytes es un poco peor de lo que esperaba porque un valorint
puede caber en solo 4 bytes adicionales. Usar unInteger
me cuesta una sobrecarga de memoria del 300 por ciento en comparación con cuando puedo almacenar el valor como un tipo primitivo
Long
: 16 bytes también: Claramente, el tamaño real del objeto en el montón está sujeto a la alineación de memoria de bajo nivel realizada por una implementación de JVM particular para un tipo de CPU particular. Parece que unLong
es 8 bytes de sobrecarga de Objeto, más 8 bytes más para el valor real real. En contraste,Integer
tenía un orificio de 4 bytes no utilizado, muy probablemente porque la JVM I usa la alineación del objeto de fuerzas en un límite de palabra de 8 bytes.
Otros contenedores son costosos también:
Arreglos multidimensionales : ofrece otra sorpresa.
Los desarrolladores comúnmente emplean construcciones comoint[dim1][dim2]
en computación numérica y científica.En una instancia de matriz
int[dim1][dim2]
, cada matrizint[dim2]
es unObject
por derecho propio. Cada uno agrega la sobrecarga de matriz de 16 bytes habitual. Cuando no necesito una matriz triangular o irregular, eso representa una sobrecarga pura. El impacto crece cuando las dimensiones de la matriz son muy diferentes.Por ejemplo, una instancia de
int[128][2]
toma 3,600 bytes. En comparación con los 1,040 bytes que utiliza una instanciaint[256]
(que tiene la misma capacidad), 3,600 bytes representan una sobrecarga del 246 por ciento. En el caso extremo debyte[256][1]
, ¡el factor de sobrecarga es casi 19! Compare eso con la situación de C / C ++ en la que la misma sintaxis no agrega ninguna sobrecarga de almacenamiento.
String
: el crecimiento de la memoria de unaString
sigue el crecimiento de la matriz de caracteres interna. Sin embargo, la claseString
agrega otros 24 bytes de sobrecarga.Para una
String
no vacía de tamaño de 10 caracteres o menos, el costo adicional agregado relativo a la carga útil (2 bytes para cada carácter más 4 bytes para la longitud), varía de 100 a 400 por ciento.
Alineación
Considere este objeto de ejemplo :
class X { // 8 bytes for reference to the class definition
int a; // 4 bytes
byte b; // 1 byte
Integer c = new Integer(); // 4 bytes for a reference
}
Una suma ingenua sugeriría que una instancia de X
usaría 17 bytes. Sin embargo, debido a la alineación (también llamada relleno), la JVM asigna la memoria en múltiplos de 8 bytes, por lo que en lugar de 17 bytes asignaría 24 bytes.