Почему это система.arraycopy родной в Java?
Я был удивлен, увидев в источнике Java эту систему.arraycopy собственный метод.
конечно, причина в том, что это быстрее. Но какие собственные трюки может использовать код, чтобы сделать его быстрее?
Почему бы просто не перебрать исходный массив и скопировать каждый указатель на новый массив-конечно, это не так медленно и громоздко?
5 ответов:
в машинном коде это можно сделать с помощью одного
memcpy
/memmove
, а не n разные операции копирования. Разница в производительности существенна.
это не может быть написано на Java. Машинный код способен игнорировать или устранять разницу между массивами объектов и массивами примитивов. Java не может этого сделать, по крайней мере, не эффективно.
и не могу пишется с одним
memcpy()
из-за семантики требует дублирования массивов.
Это, конечно, зависит от реализации.
HotSpot будет рассматривать его как" внутренний " и вставлять код на сайте вызова. Это машинный код, а не медленный старый код C. Это также означает, что проблемы с подписью метода в значительной степени уходят.
простой цикл копирования достаточно прост, чтобы к нему можно было применить очевидные оптимизации. Например, разворачивание цикла. Именно то, что происходит, снова зависит от реализации.
в моей собственной тестовой системе.arraycopy() для копирования многомерных массивов в 10-20 раз быстрее, чем чередование для циклов:
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); } } }
печатается:
System.arraycopy() duration: 1 ms loop duration: 16 ms
есть несколько причин:
JIT вряд ли будет генерировать такой же эффективный низкоуровневый код, как написанный вручную код C. Использование низкого уровня C может позволить много оптимизаций, которые почти невозможно сделать для универсального JIT-компилятора.
см. эту ссылку для некоторых трюков и сравнения скорости рукописных реализаций C (memcpy, но принцип тот же): проверьте это оптимизация Memcpy улучшается скорость
версия C в значительной степени независима от типа и размера элементов массива. Это невозможно сделать то же самое в java, так как нет никакого способа получить содержимое массива в виде необработанного блока памяти (например. указатель.)