eden - java memory model
String vs char (4)
En la JVM, una variable de caracteres se almacena en una única asignación de memoria de 16 bits y los cambios en esa variable Java sobrescriben esa misma ubicación de memoria. Esto hace que la creación o actualización de variables de caracteres sea muy rápida y barata, pero aumenta la sobrecarga de la JVM en comparación con la asignación estática tal como se usa en Strings.
La JVM almacena Java Strings en un espacio de memoria de tamaño variable (esencialmente una matriz), que tiene exactamente el mismo tamaño (más 1, para el carácter de terminación de cadena) de la cadena cuando se crea el objeto String o se le asigna un valor por primera vez. Por lo tanto, un objeto con valor inicial "¡AYUDA!" se asignarán 96 bits de almacenamiento (6 caracteres, cada uno de 16 bits de tamaño). Este valor se considera inmutable, lo que permite a la JVM hacer referencias en línea a esa variable, lo que hace que las asignaciones de cadenas estáticas sean muy rápidas, muy compactas y muy eficientes desde el punto de vista de la JVM.
Tengo algunas diapositivas de IBM con el nombre: "De Java Code a Java Heap: Understanding the Memory Usage of Your Application" , que dice, cuando usamos String
lugar de char[]
, hay
¡La sobrecarga máxima sería 24: 1 para un solo personaje!
pero no puedo entender qué sobrecarga se refiere aquí. ¿Alguien puede ayudarme?
Fuente :
Esta figura se relaciona con JDK 6- 32-bit.
JDK 6
En las cadenas mundiales anteriores a Java-7 que se implementaron como un puntero a una región de una matriz char[]
:
// "8 (4)" reads "8 bytes for x64, 4 bytes for x32"
class String{ //8 (4) house keeping + 8 (4) class pointer
char[] buf; //12 (8) bytes + 2 bytes per char -> 24 (16) aligned
int offset; //4 bytes -> three int
int length; //4 bytes -> fields align to
int hash; //4 bytes -> 16 (12) bytes
}
Así que conté:
36 bytes per new String("a") for JDK 6 x32 <-- the overhead from the article
56 bytes per new String("a") for JDK 6 x64.
JDK 7
Solo para comparar, en JDK 7+ String
es una clase que contiene un búfer char[]
y un campo hash
solamente.
class String{ //8 (4) + 8 (4) bytes -> 16 (8) aligned
char[] buf; //12 (8) bytes + 2 bytes per char -> 24 (16) aligned
int hash; //4 bytes -> 8 (4) aligned
}
Entonces es:
28 bytes per String for JDK 7 x32
48 bytes per String for JDK 7 x64.
ACTUALIZAR
Para 3.75:1
relación de 3.75:1
, vea la explicación de @Areyrey a continuación. Esta proporción cae a 1 a medida que crece la longitud de la cuerda.
Enlaces útiles:
- Uso de memoria de cadenas de Java y objetos relacionados con cadenas .
- Calcule la memoria de una entrada de mapa : una técnica simple para obtener el tamaño de un objeto.
Leí de la antigua respuesta de no pude obtenerlo. En JDK de Oracle, una cadena tiene cuatro campos de nivel de instancia:
A character array
An integral offset
An integral character count
An integral hash value
Esto significa que cada Cadena introduce una referencia de objeto adicional (la Cadena misma) y tres enteros además de la matriz de caracteres en sí misma. (La compensación y el recuento de caracteres están ahí para permitir el uso compartido de la matriz de caracteres entre las instancias String producidas mediante los métodos String # substring (), una opción de diseño que otros implementadores de bibliotecas Java han evitado). Además del costo adicional de almacenamiento, también hay uno más nivel de indirección de acceso, sin mencionar la comprobación de límites con la cual el String protege su matriz de caracteres.
Si puede salirse con la asignación y el consumo de la matriz de caracteres básicos, hay espacio para guardar allí. Sin embargo, no es idiomático hacerlo en Java; los comentarios juiciosos estarían justificados para justificar la elección, de preferencia con mención de evidencia por haber perfilado la diferencia.
Trataré de explicar los números a los que se hace referencia en el artículo original.
El artículo describe metadatos de objetos que generalmente constan de: clase, indicadores y bloqueo.
La clase y el bloqueo se almacenan en el encabezado del objeto y toman 8 bytes en la máquina virtual de 32 bits. No he encontrado ninguna información sobre implementaciones de JVM que tenga información de banderas en el encabezado del objeto. Puede ser que esté almacenado en algún lugar externo (p. Ej., Un recolector de basura para contar referencias al objeto, etc.).
Asumamos que el artículo habla de x32 AbstractJVM que usa 12 bytes de memoria para almacenar metainformación sobre el objeto.
Entonces para char[]
tenemos:
- 12 bytes de metainformación (8 bytes en x32 JDK 6, 16 bytes en x64 JDK)
- 4 bytes para el tamaño de la matriz
- 2 bytes por cada personaje almacenado
- 2 bytes de alineación si el número de caracteres es impar (en x64 JDK:
2 * (4 - (length + 2) % 4)
)
Para java.lang.String
tenemos:
- 12 bytes de metainformación (8 bytes en x32 JDK6, 16 bytes en x64 JDK6)
- 16 bytes para los campos String (es así para JDK6, 8 bytes para JDK7)
- memoria necesaria para almacenar char [] como se describió anteriormente
Entonces, vamos a contar cuánta memoria se necesita para almacenar "MyString"
como objeto String
:
12 + 16 + (12 + 4 + 2 * "MyString".length + 2 * ("MyString".length % 2)) = 60 bytes.
Por otro lado, sabemos que para almacenar solo los datos (sin información sobre el tipo de datos, la longitud o cualquier otra cosa) necesitamos:
2 * "MyString".length = 16 bytes
La altura es 60/16 60 / 16 = 3.75
De manera similar para una matriz de caracteres individuales obtenemos la ''sobrecarga máxima'':
12 + 16 + (12 + 4 + 2 * "a".length + 2 * ("a".length % 2)) = 48 bytes
2 * "a".length = 2 bytes
48 / 2 = 24
Siguiendo la lógica de los autores del artículo, en última instancia, la sobrecarga máxima del valor infinito se logra cuando almacenamos una cadena vacía :).