2012-12-18 6 views
12

Mögliche Duplizieren:
What makes JNI calls slow?Overhead eines Java JNI nennen

Zuerst mir sagen lassen, dass diese Fragen geboren ist, mehr aus Neugier als echte Notwendigkeit.

Ich bin neugierig zu wissen, was ist der Overhead bei einem JNI-Aufruf von Java, mit sagen, System.arraycopy gegenüber Zuteilung des Arrays und Kopieren der Elemente über mit einer for-Schleife.

Wenn der Aufwand erheblich ist, dann ist es wahrscheinlich eine grobe „magische Zahl“ von Elementen, bis zu der sie kompensiert einfach eine for-Schleife zu verwenden, anstatt den Systemaufruf zu verwenden. Und was genau bewirkt der Systemaufruf, der diesen Overhead verursacht? Ich vermute, der Stack muss in den Kontext des Aufrufs geschoben werden, und das könnte eine Weile dauern, aber ich kann keine gute Erklärung für den gesamten Prozess finden.

Lassen Sie mich meine Frage klären:

Ich weiß, dass arraycopy mit der schnellste Weg ist ein Array in Java zu kopieren.

aber sagen, dass wir sagen, dass ich es bin mit einem Array aus nur einem Element zu kopieren. Da ich das zugrunde liegende Betriebssystem dazu aufrufe, hat , um ein Overhead in diesem Anruf zu sein. Ich bin interessiert zu wissen, was dieser Overhead ist und was im Prozess des Anrufs passiert.

Es tut mir leid, wenn mit arraycopy Sie aus dem Sinn und Zweck meiner Frage verleitet. Ich bin interessiert, den Overhead eines JNI-Anrufs zu kennen, und was am eigentlichen Anruf beteiligt ist.

+1

Wohlgemerkt, 'System'-Aufruf ist ein etwas verwirrender Begriff, da er fälschlicherweise für einen [Systemaufruf] (https://en.wikipedia.org/wiki/System_call) gehalten werden könnte. –

+0

Übrigens gibt es eine Fülle von Informationen in http://stackoverflow.com/questions/2772152/why-is-system-arraycopy-native-in-java – NPE

+2

Gelöschte meine Antwort, ich denke, das wird Ihnen helfen: http: //stackoverflow.com/questions/7699020/what-makes-jni-calls-slow –

Antwort

9

Da ich das zugrunde liegende Betriebssystem bin Aufruf, dies zu tun ...

Sie haben Recht, dass system calls ziemlich teuer sind.Jedoch ist die System in System.arraycopy() ein bisschen falsch. Es sind keine Systemaufrufe beteiligt.

... in diesem Anruf muss ein Overhead vorliegen. Ich bin interessiert zu wissen, was dieser Overhead ist und was im Prozess des Anrufs passiert.

Wenn Sie bei der Definition von System.arraycopy() aussehen, ist es als native erklärt. Dies bedeutet, dass die Methode in C++ implementiert ist. Wenn Sie so geneigt sind, könnten Sie den JDK-Quellcode betrachten und die C++ - Funktion finden. In OpenJDK 7 heißt es JVM_ArrayCopy() und lebt in hotspot/src/share/vm/prims/jvm.cpp. Die Implementierung ist überraschend kompliziert, aber im Grunde ist es im Wesentlichen ein memcpy().

Wenn arraycopy() als normale native Funktion verwendet wird, gibt es einen Overhead für den Aufruf. Es gibt einen weiteren Overhead, der durch eine Überprüfung der Argumente usw. verursacht wird.

Es ist jedoch sehr wahrscheinlich, dass die JIT compiler über System.arraycopy() weiß. Dies bedeutet, dass der Compiler, anstatt die C++ - Funktion aufzurufen, weiß, wie speziell erzeugter Maschinencode zum Ausführen der Array-Kopie erzeugt wird. Ich weiß nicht, über andere JVMs, aber HotSpot hat solche "intrinsische" Unterstützung für System.arraycopy().

Lassen Sie uns sagen, dass ich es bin mit nur ein Array von einem Element kopieren

Wenn Ihr Array ist winzig, können Sie in der Lage sein System.arraycopy() mit einem handgefertigten Schleife zu schlagen. Sie können es wahrscheinlich noch besser machen, wenn die Größe zur Kompilierzeit bekannt ist, da Sie dann die Schleife auch abrollen können. Das alles ist jedoch nur in den engsten Umständen wirklich relevant.

+0

+1 Der Punkt über Inlining einen nativen Anruf ist der wichtigste Beitrag. –

+0

Ihre Antwort, zusammen mit der Kommentar, der mich darauf hinweist: http://StackOverflow.com/Questions/7699020/What-Makes-Jni-Calls-Slow ist am hilfreichsten gewesen, also nehme ich an. Danke, dass Sie ein paar Begriffe geläutert haben, die ich nicht kannte. Ich stelle es sehr deutlich dar. – pcalcao

+1

+1 eine der besten Antworten, die ich für jede Frage gesehen habe – Bohemian

0

Sie haben es falsch herum. System.arraycopy() ist eine superschnelle native Implementierung durch die

JVM bereitgestellt

Es gibt keinen „Overhead“ - es gibt nur „Vorteil“

2

Werfen Sie einen Blick auf java.util.Arrays.copyOf Implementierungen, zB

public static byte[] copyOf(byte[] original, int newLength) { 
    byte[] copy = new byte[newLength]; 
    System.arraycopy(original, 0, copy, 0, 
        Math.min(original.length, newLength)); 
    return copy; 
} 

Sie verwenden System.arraycopy, weil dies der schnellste Weg ist.

Wenn Sie meinen, ob Aufruf native Methoden in Java ist teuer dann einen Blick auf http://www.javamex.com/tutorials/jni/overhead.shtml

UPDATE Frage wirklich interessant ist, also habe ich einige Tests gemacht

 long t0 = System.currentTimeMillis(); 
     byte[] a = new byte[100]; 
     byte[] b = new byte[100]; 
     for(int i = 0; i < 10000000; i++) { 
//   for(int j = 0; j < a.length; j++) { 
//    a[j] = b[j]; 
//   } 
      System.arraycopy(b, 0, a, 0, a.length); 
     } 
     System.out.println(System.currentTimeMillis() - t0); 

Es zeigt, dass auf sehr kurzen Arrays (< 10) System.arraycopy möglicherweise noch langsamer, höchstwahrscheinlich, weil es nativ ist, aber auf größeren Arrays spielt es keine Rolle mehr, System.arraycopy ist viel schneller.

+0

Danke, uplooted für den Link, das war in der Tat, was ich gesucht habe. – pcalcao

+0

Ich habe einige Tests hinzugefügt, siehe mein Update –

+0

* "...wahrscheinlich, weil es nativ ist "* - es gibt andere mögliche Erklärungen, zB wegen der Buchführung, die' arraycopy() 'zu tun hat, um die Argumente zu überprüfen, und wählen Sie die richtige Art der Kopie. –

1

Ich bin interessiert, den Overhead eines JNI-Anrufs zu kennen, und was in den tatsächlichen Anruf involviert ist.

Die System.arraycopy() Verfahren ist ziemlich kompliziert * und es ist unwahrscheinlich, dass der JIT-Compiler inlines es (als eine der anderen Antworten schon sagt).

Auf der anderen Seite ist es wahrscheinlich, dass der JIT-Compiler eine optimierte Aufrufsequenz verwendet, da dies eine intrinsische native Methode ist. Mit anderen Worten, dies ist höchstwahrscheinlich kein normaler JNI-Aufruf.


* - System.arraycopy ist keine einfache Speicherkopie. Es muss seine Argumente testen, um das Lesen oder Schreiben über die Array-Grenzen hinaus zu vermeiden, und so weiter. Und in dem Fall, wenn Sie von einem Objekt-Array zu einem anderen kopieren es kann müssen überprüfen, dass der tatsächliche Typ der einzelnen Objekte kopiert. All dies summiert sich zu weit mehr Code, als es sinnvoll ist, inline zu erstellen.