son sistema que programas programacion para operativo maquina los invocar interprete instruccion implicaciones encargados ejemplos cualquier cual corran compilados caracteristicas java jvm

java - sistema - ¿Cómo se almacenan las matrices enteros internamente en la JVM?



que es la jvm de java y sus implicaciones (5)

Una matriz de entradas en Java se almacena como un bloque de valores de 32 bits en la memoria. ¿Cómo se almacena una matriz de objetos enteros? es decir

int[] vs. Integer[]

Me imagino que cada elemento en la matriz Integer es una referencia a un objeto Integer, y que el objeto Integer tiene objetos de almacenamiento de objetos, al igual que cualquier otro objeto.

Sin embargo, espero que la JVM haga algo de ingenio mágico bajo la cubierta dado que los enteros son inmutables y lo almacena como una serie de enteros.

¿Es mi esperanza lamentablemente ingenua? ¿Es una matriz Integer mucho más lenta que una matriz int en una aplicación donde importa hasta el último gramo de rendimiento?


Creo que tu esperanza es lamentablemente ingenua. Específicamente, necesita tratar el problema de que Integer puede ser nulo, mientras que int no puede ser. Solo eso es razón suficiente para almacenar el puntero del objeto.

Dicho esto, el puntero del objeto real será una instancia int inmutable, especialmente para un subconjunto seleccionado de enteros.


John Rose trabajando en fixnums en la JVM para solucionar este problema.


La razón por la que Integer puede ser nulo, mientras que int no puede, es porque Integer es un objeto Java de pleno derecho, con todos los gastos generales que incluye. Hay valor en esto ya que puedes escribir

Integer foo = new Integer(); foo = null;

lo cual es bueno para decir que foo tendrá un valor, pero aún no.

Otra diferencia es que int no realiza ningún cálculo de desbordamiento. Por ejemplo,

int bar = Integer.MAX_VALUE; bar++;

aumentará alegremente la barra y terminarás con un número muy negativo, que probablemente no sea lo que pretendías en primer lugar.

foo = Integer.MAX_VALUE; foo++;

se quejará, lo cual creo que sería un mejor comportamiento.

Un último punto es que Integer, al ser un objeto Java, lleva consigo la sobrecarga del espacio de un objeto. Creo que alguien más puede necesitar entrar aquí, pero creo que cada objeto consume 12 bytes de sobrecarga, y luego el espacio para el almacenamiento de datos en sí. Si buscas rendimiento y espacio, me pregunto si Integer es la solución correcta.


Ninguna VM que conozco almacenará una matriz Integer [] como una matriz int [] por los siguientes motivos:

  1. Puede haber objetos enteros nulos en la matriz y no le quedan bits para indicar esto en una matriz int. Sin embargo, la VM podría almacenar esta información de 1 bit por ranura de matriz en una matriz de bits oculta.
  2. Puede sincronizar en los elementos de una matriz de enteros. Esto es mucho más difícil de superar que el primer punto, ya que tendría que almacenar un objeto de monitor para cada ranura de matriz.
  3. Los elementos de Integer [] se pueden comparar para la identidad. Por ejemplo, podría crear dos objetos enteros con el valor 1 a través de nuevos y almacenarlos en diferentes ranuras de matriz y luego recuperarlos y compararlos a través de ==. Esto debe conducir a falso, por lo que tendría que almacenar esta información en algún lugar. O mantenga una referencia a uno de los objetos enteros en alguna parte y utilícelo para la comparación y debe asegurarse de que una de las comparaciones == sea falsa y una verdadera. Esto significa que todo el concepto de identidad de objeto es muy difícil de manejar para la matriz de enteros optimizada .
  4. Puede convertir un Entero [] a, por ejemplo, Objeto [] y pasarlo a métodos que esperan solo un Objeto []. Esto significa que todo el código que maneja Object [] ahora también debe poder manejar el objeto entero Integer [] también, haciéndolo más lento y más grande.

Tomando todo esto en cuenta, probablemente sería posible hacer un Entero especial [] que ahorra espacio en comparación con una implementación ingenua , pero la complejidad adicional probablemente afectará a muchos otros códigos, haciéndolo más lento al final.

La sobrecarga de usar Integer [] en lugar de int [] puede ser bastante grande en espacio y tiempo. En una VM típica de 32 bits, un objeto entero consumirá 16 bytes (8 bytes para el encabezado del objeto, 4 para la carga útil y 4 bytes adicionales para la alineación), mientras que el entero [] usa tanto espacio como int []. En las máquinas virtuales de 64 bits (con punteros de 64 bits, que no siempre es el caso), un objeto entero consumirá 24 bytes (16 para el encabezado, 4 para la carga útil y 4 para la alineación). Además, una ranura en el entero [] usará 8 bytes en lugar de 4 como en el int []. Esto significa que puede esperar una sobrecarga de 16 a 28 bytes por ranura, que es un factor de 4 a 7 en comparación con las matrices simples en línea.

La sobrecarga de rendimiento también puede ser significativa principalmente por dos motivos:

  1. Dado que usa más memoria, ejerce mucha más presión sobre el subsistema de memoria, lo que aumenta las probabilidades de que falte el caché en el caso de Integer []. Por ejemplo, si recorre los contenidos de int [] de forma lineal, la memoria caché tendrá la mayoría de las entradas ya tomadas cuando las necesite (ya que el diseño también es lineal). Pero en el caso de la matriz Integer, los objetos Integer se pueden dispersar aleatoriamente en el montón, lo que dificulta que la memoria cache adivine a dónde apuntará la siguiente referencia de memoria.
  2. La recolección de basura tiene que hacer mucho más trabajo debido a la memoria adicional utilizada y porque tiene que escanear y mover cada objeto entero por separado, mientras que en el caso de int [] es solo un objeto y el contenido del objeto no lo hace tienen que ser escaneados (no contienen referencia a otros objetos).

En resumen, usar un int [] en el trabajo crítico de rendimiento será mucho más rápido y más eficiente en cuanto a la memoria que usar una matriz Integer en las máquinas virtuales actuales y es poco probable que esto cambie mucho en el futuro cercano.


No será mucho más lento, pero como un entero [] debe aceptar "nulo" como una entrada y int [] no tiene que hacerlo, habrá cierta cantidad de contabilidad involucrada, incluso si Integer [] está respaldado por un En t[].

Entonces, si cada onza de rendimiento es importante, el usuario int []