¿Cómo obtiene la JVM la longitud de la matriz?

¿Cómo obtiene la JVM la longitud de la matriz?

Esta nota registra principalmente las matrices que escribimos en java, como int arr [] = {1,2,3};, luego usamos int len ​​= arr.length; cómo el jvm subyacente obtiene la longitud de la
matriz ; la matriz está en La capa inferior de jvm se genera dinámicamente, lo que significa que no es estática. Es similar al código hash de un objeto. Si no ha anulado el método hashcode, el código hash del objeto es la dirección de memoria del objeto por defecto, por lo que el código hash también se genera dinámicamente , Nuestra matriz es la misma. Después de definir la matriz, la matriz se puede generar, agregar y eliminar dinámicamente en tiempo de ejecución, por lo que la longitud de la matriz también se genera dinámicamente; aquí usamos el programa y HSDB para probar la matriz Cómo obtener la longitud en la parte inferior del jvm, primero mire el siguiente programa:

public class T0819 {
    
    


    public static void main(String[] args) {
    
    
        int arr [] ={
    
    1,2,3};
        int length = arr.length;
        System.out.println(length);
    }
}

Revisemos la información del código de bytes a través de javap -verbose T0819.class

public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=3, args_size=1
         0: iconst_3
         1: newarray       int
         3: dup
         4: iconst_0
         5: iconst_1
         6: iastore
         7: dup
         8: iconst_1
         9: iconst_2
        10: iastore
        11: dup
        12: iconst_2
        13: iconst_3
        14: iastore
        15: astore_1
        16: aload_1
        17: arraylength
        18: istore_2
        19: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        22: iload_2
        23: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
        26: return
      LineNumberTable:
        line 7: 0
        line 8: 16
        line 9: 19
        line 10: 26
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      27     0  args   [Ljava/lang/String;
           16      11     1   arr   [I
           19       8     2 length   I
}

Mire el contador del programa 17, arraylength. Para decirlo sin rodeos, averiguar cómo se obtiene dinámicamente la longitud de la matriz en el jvm depende de cómo el jvm procesa la instrucción de código de bytes arraylength; aquí encontré un bloque de código de cómo openjdk obtiene la longitud de la matriz :

CASE(_arraylength):
{
    
    
  arrayOop ary = (arrayOop) STACK_OBJECT(-1);
  CHECK_NULL(ary);
  SET_STACK_INT(ary->length(), -1);
  UPDATE_PC_AND_CONTINUE(1);
}


int length() const {
    
    
    return *(int*)(((intptr_t)this) + length_offset_in_bytes());
 }

El código CASE es obtener la longitud de nuestra matriz. La tercera línea de código en el caso es obtener la longitud y colocarla en la pila.
Principalmente analizamos el método length (), que usa el puntero this para obtener la primera posición de la matriz, y luego agregamos El desplazamiento de la matriz se agrega para obtener la longitud de nuestra matriz, miramos la siguiente figura:
Inserte la descripción de la imagen aquí
((intptr_t) this) = obtener la primera posición de nuestra matriz
length_offset_in_bytes () = obtener el desplazamiento de nuestra matriz en la memoria
y luego agregar , Toma la dirección y obtén la longitud de nuestra matriz

Veamos la función length_offset_in_bytes () para obtener el desplazamiento

//如果不压缩,则在arrayOopDesc中声明的非静态字段之后分配
//如果压缩,它将占用oopDesc中_klass字段的后半部分
static int length_offset_in_bytes() {
    
    
    return UseCompressedClassPointers ? klass_gap_offset_in_bytes() :
                               sizeof(arrayOopDesc);
  }

Mire el código anterior, hay un parámetro UseCompressedClassPointers, este parámetro también es parte de nuestro ajuste de jvm, ¿qué significa este parámetro? Sabemos por las notas anteriores que nuestro diseño de memoria de objetos tiene un encabezado de objeto, datos de instancia y relleno de alineación;
y el encabezado de objeto se divide en palabra de marca, puntero de tipo y longitud de matriz, y la compresión de puntero de tipo y los bytes sin comprimir no lo son Lo mismo,
entonces , ¿cuál es la diferencia entre UseCompressedClassPointers y UseCompressedoops?
UseCompressedoops comprime la longitud del puntero del objeto, mientras que UseCompressedClassPointers comprime la longitud del puntero del objeto Klass. Si habilitamos UseCompressedoops, entonces UseCompressedClassPointers está activado de forma predeterminada, lo que
significa que UseCompressedoops incluye UseCompressedClassPointers.
Primero, analicemos la matriz: el
Klass correspondiente es: instancia de TypeArrayKlass El
oop correspondiente es: instancia de TypeArrayOop

Y el bloque de código del puntero de tipo en jvm es:

union _metadata {
    
    
    Klass*      _klass;         8B
    narrowKlass _compressed_klass;    4B
  } _metadata;

Es un consorcio, todo el consorcio ocupa 8B de espacio, si estamos comprimidos, entonces se usará 4B, si no comprimimos, entonces se usará 8B, entonces si comprimimos, ¿es una pérdida de espacio? El comentario del método length_offset_in_bytes () ha sido escrito, comenzaremos a analizar todo el problema a continuación.
Disposición de la memoria de
objetos Encabezado del objeto
Marca Palabra
Puntero de Klass
Longitud de la matriz
Datos de la instancia
Relleno

Si habilitamos la compresión del puntero:
Marque Word 8B
Puntero Klass 4B
longitud de la matriz 4B
luego longitud del puntero + longitud de la matriz = 4B + 4B = 8B
si no comprimimos es = 8B + 4B = 12B

Entonces entendemos la oración en los comentarios de código "Si está comprimido, ocupará la segunda mitad del campo _klass en oopDesc".
Si está comprimido, el puntero de tipo es 4B, porque nuestro

union _metadata {
    
    
    Klass*      _klass;         8B
    narrowKlass _compressed_klass;    4B
  } _metadata;

Es 8B. Comprimido y usado es _compressed_klass en la unión, y nuestra longitud de matriz es 4B, por lo que usamos 4B en la segunda mitad de _klass, lo que significa que, es decir, nuestra longitud de matriz es La segunda mitad de la unión, si la compresión del puntero está activada.

Pasamos a través de nuestra longitud de matriz HSDB para ver lo siguiente:
Inserte la descripción de la imagen aquí
estamos en compresión de puntero abierto, es --metadata._compressed_klass, veamos la siguiente vista de memoria:
Inserte la descripción de la imagen aquí
cerramos la compresión de puntero: -XX: -UseCompressedClassPointers
Inserte la descripción de la imagen aquí
a fancy La imagen es para saber que la compresión del puntero está desactivada.
Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/scjava/article/details/108219216
Recomendado
Clasificación