¿Por qué System.arraycopy es nativo en Java?

Me sorprendió ver en la fuente de Java que System.arraycopy es un método nativo.

Por supuesto, la razón es porque es más rápido. Pero, ¿qué trucos nativos puede usar el código para hacerlo más rápido?

¿Por qué no simplemente recorre la matriz original y copia cada puntero a la nueva matriz, seguramente esto no es tan lento y engorroso?

En el código nativo, se puede hacer con un único memcpy / memmove , en oposición a n operaciones de copia distintas. La diferencia en el rendimiento es sustancial.

No puede escribirse en Java. El código nativo puede ignorar o eludir la diferencia entre matrices de objetos y matrices de primitivas. Java no puede hacer eso, al menos no de manera eficiente.

Y no se puede escribir con un solo memcpy() , debido a la semántica requerida por la superposición de matrices.

Por supuesto, depende de la implementación.

HotSpot lo tratará como un código “intrínseco” e insertado en el sitio de llamadas. Eso es código de máquina, no código de C viejo lento. Esto también significa que los problemas con la firma del método desaparecen en gran parte.

Un simple ciclo de copia es lo suficientemente simple como para aplicarle optimizaciones obvias. Por ejemplo, desenrollar bucles. Exactamente lo que sucede depende nuevamente de la implementación.

En mis propias pruebas, System.arraycopy () para copiar matrices de múltiples dimensiones es de 10 a 20 veces más rápido que el entrelazado de bucles:

 float[][] foo = mLoadMillionsOfPoints(); // result is a float[1200000][9] float[][] fooCpy = new float[foo.length][foo[0].length]; long lTime = System.currentTimeMillis(); System.arraycopy(foo, 0, fooCpy, 0, foo.length); System.out.println("native duration: " + (System.currentTimeMillis() - lTime) + " ms"); lTime = System.currentTimeMillis(); for (int i = 0; i < foo.length; i++) { for (int j = 0; j < foo[0].length; j++) { fooCpy[i][j] = foo[i][j]; } } System.out.println("System.arraycopy() duration: " + (System.currentTimeMillis() - lTime) + " ms"); for (int i = 0; i < foo.length; i++) { for (int j = 0; j < foo[0].length; j++) { if (fooCpy[i][j] != foo[i][j]) { System.err.println("ERROR at " + i + ", " + j); } } } 

Esto imprime:

 System.arraycopy() duration: 1 ms loop duration: 16 ms 

Hay unas pocas razones:

  1. Es improbable que el JIT genere un código eficiente de bajo nivel como un código C escrito manualmente. Usar bajo nivel C puede permitir muchas optimizaciones que son casi imposibles de hacer para un comstackdor JIT genérico.

    Consulte este enlace para ver algunos trucos y comparaciones de velocidad de las implementaciones de C escritas a mano (memcpy, pero el principio es el mismo): Compruebe esto Optimizing Memcpy mejora la velocidad

  2. La versión C es bastante independiente del tipo y tamaño de los miembros de la matriz. No es posible hacer lo mismo en Java ya que no hay forma de obtener los contenidos de la matriz como un bloque de memoria sin formato (por ejemplo, un puntero).

Intereting Posts