55 votes

La méthode System.arraycopy () de Java est-elle efficace pour les petits tableaux?

Est-ce que Java est System.arraycopy() efficace pour les petits tableaux, ou est-ce que c'est une méthode native qui la rend probablement beaucoup moins efficace qu'une simple boucle et un appel de fonction?

Les méthodes natives entraînent-elles une surcharge de performances supplémentaire lors de la traversée d'un pont de type système Java?

28voto

vanza Points 4391

Étendre un peu sur ce que Sid a écrit, il est très probable qu' System.arraycopy est juste un JIT intrinsèque; ce qui signifie que lorsque les appels de code System.arraycopy, il sera très probablement être d'appeler un JIT de mise en œuvre (une fois que le JIT étiquettes System.arraycopy comme étant "à chaud") qui n'est pas exécuté par le biais de l'interface JNI, afin de ne pas encourir la normale surcharge des méthodes indigènes.

En général, l'exécution des méthodes indigènes n'ont que des frais généraux (en passant par l'interface JNI, ainsi que l'intérieur de la JVM des opérations ne peut pas se produire lorsque des méthodes indigènes sont en train d'être exécuté). Mais ce n'est pas parce qu'une méthode est marqué comme "indigènes", que vous êtes réellement l'exécuter en utilisant JNI. L'équipe peut faire des choses folles.

La plus simple façon de le vérifier est, comme cela a été suggéré, à écrire un petit indice de référence, en faisant attention à la normale mises en garde de Java microbenchmarks (réchauffer le code tout d'abord, éviter de code avec aucun des effets secondaires depuis le JIT juste optimise comme un no-op, etc).

24voto

Ethaniel Points 141

Voici mon code de référence:

public void test(int copySize, int copyCount, int testRep) {
    System.out.println("Copy size = " + copySize);
    System.out.println("Copy count = " + copyCount);
    System.out.println();
    for (int i = testRep; i > 0; --i) {
        copy(copySize, copyCount);
        loop(copySize, copyCount);
    }
    System.out.println();
}

public void copy(int copySize, int copyCount) {
    int[] src = newSrc(copySize + 1);
    int[] dst = new int[copySize + 1];
    long begin = System.nanoTime();
    for (int count = copyCount; count > 0; --count) {
        System.arraycopy(src, 1, dst, 0, copySize);
        dst[copySize] = src[copySize] + 1;
        System.arraycopy(dst, 0, src, 0, copySize);
        src[copySize] = dst[copySize];
    }
    long end = System.nanoTime();
    System.out.println("Arraycopy: " + (end - begin) / 1e9 + " s");
}

public void loop(int copySize, int copyCount) {
    int[] src = newSrc(copySize + 1);
    int[] dst = new int[copySize + 1];
    long begin = System.nanoTime();
    for (int count = copyCount; count > 0; --count) {
        for (int i = copySize - 1; i >= 0; --i) {
            dst[i] = src[i + 1];
        }
        dst[copySize] = src[copySize] + 1;
        for (int i = copySize - 1; i >= 0; --i) {
            src[i] = dst[i];
        }
        src[copySize] = dst[copySize];
    }
    long end = System.nanoTime();
    System.out.println("Man. loop: " + (end - begin) / 1e9 + " s");
}

public int[] newSrc(int arraySize) {
    int[] src = new int[arraySize];
    for (int i = arraySize - 1; i >= 0; --i) {
        src[i] = i;
    }
    return src;
}

De mes tests, appelant test() avec copyCount = 10000000 (1e7) ou plus permet le warm-up pour être réalisée lors de la première copy/loop appel, donc à l'aide d' testRep = 5 est assez; Avec copyCount = 1000000 (1e6) le warm-up besoin d'au moins 2 ou 3 itérations afin testRep doit être augmenté afin d'obtenir des résultats utilisables.

Avec ma configuration (PROCESSEUR Intel Core 2 Duo E8500 @ 3.16 GHz, Java SE 1.6.0_35-b10 et Eclipse 3.7.2) il ressort de l'indice de référence qui:

  • Lors de l' copySize = 24, System.arraycopy() "et le" manuel de la boucle de prendre presque dans le même temps (parfois on est très légèrement plus vite que les autres, d'autres fois c'est le contraire),
  • Lors de l' copySize < 24, le manuel de la boucle est plus rapide que l' System.arraycopy() (un peu plus rapide avec copySize = 23, vraiment plus rapide avec copySize < 5),
  • Lors de l' copySize > 24, System.arraycopy() est plus rapide que le manuel de la boucle (un peu plus rapide avec copySize = 25, le ratio de la boucle en temps/arraycopy-temps, la demande croissante en tant que copySize augmente).

Note: je ne suis pas anglais langue maternelle, s'il vous plaît excusez tous mes grammaire/vocabulaire des erreurs.

19voto

irreputable Points 25577

C'est une préoccupation légitime. Par exemple, en java.nio.DirectByteBuffer.put(byte[]), l'auteur tente d'éviter un JNI copie pour un petit nombre d'éléments

// These numbers represent the point at which we have empirically
// determined that the average cost of a JNI call exceeds the expense
// of an element by element copy.  These numbers may change over time.
static final int JNI_COPY_TO_ARRAY_THRESHOLD   = 6;
static final int JNI_COPY_FROM_ARRAY_THRESHOLD = 6;

Pour System.arraycopy(), nous pouvons examiner comment JDK l'utilise. Par exemple, en ArrayList, System.arraycopy() est toujours utilisé, jamais "élément par élément de la copie", quelle que soit la durée (même si c'est 0). Depuis ArrayList la performance est très conscient, nous pouvons déduire que l' System.arraycopy() est le plus efficace moyen de la matrice de la copie quelle que soit la durée.

7voto

lichenbo Points 375

System.arraycopy utilise une opération memmove pour le déplacement de mots et l'assemblage pour le déplacement d'autres types primitifs en C derrière la scène. Il fait donc tout ce qui est en son pouvoir pour déplacer le plus efficacement possible.

5voto

Sid Malani Points 1502

Les codes d'octets sont de toute façon exécutés de manière native, il est donc probable que les performances soient meilleures qu'une boucle.

Ainsi, dans le cas d’une boucle, il devrait exécuter des codes d’octets, ce qui entraînerait une surcharge. Alors que la copie du tableau devrait être memcopy directe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X