¿Cuál es el consumo de memoria de un objeto en Java?

¿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 para un objeto?
¿Cuánto espacio adicional se usa al agregar un atributo?

Mindprod señala que esta no es una pregunta fácil de responder:

Una JVM es libre de almacenar datos de la forma que le plazca internamente, ya sean grandes o pequeños, con cualquier cantidad de relleno o sobrecarga, aunque los primitivos deben comportarse como si tuvieran los tamaños oficiales.
Por ejemplo, el comstackdor JVM o nativo podría decidir almacenar un boolean[] en fragmentos largos de 64 bits como un BitSet . No tiene que decírselo, siempre y cuando el progtwig brinde las mismas respuestas.

  • Podría asignar algunos Objetos temporales en la stack.
  • Puede optimizar algunas variables o llamadas al método totalmente fuera de existencia reemplazándolas por constantes.
  • Puede versionar métodos o bucles, es decir, comstackr dos versiones de un método, cada una optimizada para una situación determinada, y luego decidir de antemano a cuál llamar.

Luego, por supuesto, el hardware y el sistema operativo tienen cachés de varias capas, en caché de chips, caché SRAM, memoria caché DRAM, conjunto de trabajo RAM normal y almacenamiento 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.

Métodos de medición

Puede usar Instrumentation.getObjectSize() para obtener una estimación del almacenamiento consumido por un objeto.

Para visualizar el diseño del objeto real , la huella y las referencias, puede usar la herramienta JOL (Java Object Layout) .

Cabeceras de objetos y referencias de objetos

En un moderno JDK 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 las JVM de 32 bits, la tara es de 8 bytes, acolchada a un múltiplo de 4 bytes. (De la respuesta de Dmitry Spikhalskiy, la respuesta de Jayen y JavaWorld ).

Normalmente, las referencias son 4 bytes en plataformas de 32 bits o en plataformas de 64 bits hasta -Xmx32G ; y 8 bytes por encima de 32 Gb ( -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 dynamic. ( ¿Debo usar una JVM de 32 o de 64 bits?, 2012, JDK 1.7)

Tipos, matrices y cadenas en caja

Los envoltorios en caja tienen sobrecarga en comparación con los tipos primitivos (de JavaWorld ):

  • Integer : el resultado de 16 bytes es un poco peor de lo esperado porque un valor int puede caber en solo 4 bytes adicionales. Usar un Integer 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 una alineación de memoria de bajo nivel realizada por una implementación de JVM particular para un tipo de CPU en particular. Parece que un Long tiene 8 bytes de sobrecarga de Objeto, más 8 bytes más para el valor real largo. Por el contrario, Integer tenía un agujero de 4 bytes sin usar, muy probablemente porque la JVM que uso fuerza la alineación del objeto en un límite de 8 bytes.

Otros contenedores son costosos también:

  • Arrays multidimensionales : ofrece otra sorpresa.
    Los desarrolladores comúnmente emplean construcciones como int[dim1][dim2] en computación numérica y científica.

    En una instancia de matriz int[dim1][dim2] , cada matriz anidada int[dim2] es un Object por derecho propio. Cada uno agrega la sobrecarga usual de la matriz de 16 bytes. Cuando no necesito una matriz triangular o designada, eso representa una sobrecarga pura. El impacto crece cuando las dimensiones de la matriz difieren enormemente.

    Por ejemplo, una instancia int[128][2] toma 3.600 bytes. En comparación con los 1.040 bytes que usa una instancia int[256] (que tiene la misma capacidad), 3,600 bytes representan un 246 por ciento de sobrecarga. En el caso extremo de byte[256][1] , ¡el factor de sobrecarga es casi 19! Compare eso con la situación de C / C ++ en la que la misma syntax no agrega ninguna sobrecarga de almacenamiento.

  • String : el crecimiento de la memoria de una String rastrea el crecimiento de su matriz de caracteres interna. Sin embargo, la clase String agrega otros 24 bytes de sobrecarga.

    Para una String no vacía de 10 caracteres o menos, el costo indirecto agregado relativo a la carga útil útil (2 bytes para cada char más 4 bytes para la longitud), oscila entre 100 y 400 por ciento.

Alineación

Considera 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 sum 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.

Cada objeto tiene una cierta sobrecarga para su monitor asociado y la información de tipo, así como también los campos. Más allá de eso, los campos se pueden diseñar más o menos, sin embargo, la JVM lo considera apropiado (creo), pero como se muestra en otra respuesta , al menos algunas JVM se empacarán bastante. 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 tomaran 1200 bytes (8 bytes de sobrecarga + 4 bytes para el campo debido a relleno / alineación). Esperaría que una instancia de OneHundredBytes tomara 108 bytes: la sobrecarga y luego los 100 bytes empacados. Sin embargo, ciertamente 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 / rellenos). En una JVM de 64 bits, la sobrecarga también puede ser más grande (no estoy seguro).

EDITAR: Vea el comentario a continuación; aparentemente HotSpot se adapta a límites de 8 bytes en lugar de 32, por lo que cada instancia de SingleByte tomaría 16 bytes.

De cualquier manera, el “único objeto grande” será al menos tan eficiente como múltiples objetos pequeños, para casos simples como este.

Depende de la architecture / jdk. Para una architecture 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 Diseño de objetos Java para determinar un tamaño y obtener detalles sobre el diseño del objeto 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 

Por lo tanto, para Integer, el tamaño de la instancia es de 16 bytes, porque 4 bytes se compactan en su lugar justo después del encabezado y antes de rellenar el límite.

Muestra 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:

  org.openjdk.jol jol-core 0.3.2  

No, registrar un objeto también requiere un poco de memoria. 100 objetos con 1 atributo tomarán más memoria.

¿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 para 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 varían de 1 byte (char / boolean) a 8 bytes (largo / doble), pero las referencias son 4 bytes u 8 bytes, dependiendo de si es de 32 bits o 64 bits, sino 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.

La memoria total utilizada / libre de un progtwig se puede obtener en el progtwig 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 encoding 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)); } } 

Obtuve muy buenos resultados del método java.lang.instrument.Instrumentation mencionado en otra respuesta. Para ver buenos ejemplos de su uso, consulte la entrada, Contador de memoria de instrumentación del Boletín informativo de JavaSpecialists y la biblioteca java.sizeOf en SourceForge.

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.

enter image description here

http://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf también es muy informativo, por ejemplo:

enter image description here

no, 100 objetos pequeños necesitan más información (memoria) que uno grande.

En caso de que sea útil para cualquier persona, 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 de memoria “profunda”.

La pregunta será muy amplia.

Depende de la variable de clase o puede llamar como estado el uso de memoria en java.

También tiene algunos requisitos de memoria adicionales para encabezados y referencias.

La memoria de stack 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 consiste en unos pocos bytes de información de “limpieza”;

Los objetos en Java también requieren cierta información de “limpieza”, como la grabación de la clase de un objeto, ID y indicadores de estado, como si el objeto es actualmente alcanzable, actualmente está bloqueado por sincronización, etc.

El tamaño del encabezado del objeto Java varía en 32 y 64 bit jvm.

Aunque estos son los principales consumidores de memoria, jvm también requiere campos adicionales a veces como alineación del código, etc.

Tamaños de tipos primitivos

booleano y byte – 1

char y corto – 2

int y float – 4

largo y doble – 8

Las reglas sobre la cantidad de memoria consumida dependen de la implementación de JVM y de la architecture de la CPU (32 bits frente a 64 bits, por ejemplo).

Para conocer las reglas detalladas de SUN JVM, consulte mi viejo blog

Saludos, Markus

Intereting Posts