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 emplear el código que lo hacen más rápido?
¿Por qué no simplemente recorrer la matriz original y copiar cada puntero a la nueva matriz? Seguramente esto no es tan lento y engorroso.
arraycopy
podrían implementarse usandomemcpy
/memmove
. Otros requieren una verificación de tipo en tiempo de ejecución para cada elemento copiado.Object[]
pobladoString
a unString[]
. Consulte el último párrafo de java.sun.com/javase/6/docs/api/java/lang/…No se puede escribir en Java. El código nativo puede ignorar o eludir la diferencia entre matrices de Object 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 las matrices superpuestas.fuente
memmove
entonces. Aunque no creo que haya mucha diferencia en el contexto de esta pregunta.Por supuesto, depende de la implementación.
HotSpot lo tratará como un código "intrínseco" e insertará en el sitio de la llamada. Eso es código máquina, no código C antiguo lento. Esto también significa que los problemas con la firma del método desaparecen en gran medida.
Un bucle de copia simple es lo suficientemente simple como para que se le puedan aplicar optimizaciones obvias. Por ejemplo, desenrollado de bucle. Exactamente lo que sucede depende nuevamente de la implementación.
fuente
En mis propias pruebas, System.arraycopy () para copiar matrices de múltiples dimensiones es de 10 a 20 veces más rápido que intercalar para 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
fuente
System.arraycopy
hace una copia superficial (solo se copian las referencias a losfloat[]
s internos ), mientras que susfor
bucles anidados realizan una copia profunda (float
porfloat
). Un cambio enfooCpy[i][j]
se reflejará en elfoo
usoSystem.arraycopy
, pero no usará losfor
bucles anidados .Hay unas pocas razones:
Es poco probable que el JIT genere un código de bajo nivel tan eficiente como un código C escrito manualmente. El uso de C de bajo nivel puede permitir muchas optimizaciones que son casi imposibles de realizar para un compilador JIT genérico.
Consulte este enlace para ver algunos trucos y comparaciones de velocidad de implementaciones de C escritas a mano (memcpy, pero el principio es el mismo): marque esto Optimizing Memcpy mejora la velocidad
La versión C es prácticamente 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 el contenido de la matriz como un bloque de memoria sin formato (por ejemplo, puntero).
fuente