202 Stimmen

Java-Reflexionsleistung

Führt die Erstellung eines Objekts mit Hilfe von Reflexion anstelle des Aufrufs des Klassenkonstruktors zu erheblichen Leistungsunterschieden?

24voto

Marcus Downing Punkte 9754

Es gibt einen gewissen Overhead bei Reflection, aber der ist auf modernen VMs viel geringer als früher.

Wenn Sie Reflection verwenden, um jedes einfache Objekt in Ihrem Programm zu erstellen, dann stimmt etwas nicht. Wenn Sie sie gelegentlich verwenden, wenn Sie einen guten Grund haben, sollte das kein Problem sein.

13voto

mel3kings Punkte 7889

Ja, es gibt einen Leistungseinbruch bei der Verwendung von Reflection, aber ein möglicher Workaround für die Optimierung ist das Caching der Methode:

  Method md = null;     // Call while looking up the method at each iteration.
      millis = System.currentTimeMillis( );
      for (idx = 0; idx < CALL_AMOUNT; idx++) {
        md = ri.getClass( ).getMethod("getValue", null);
        md.invoke(ri, null);
      }

      System.out.println("Calling method " + CALL_AMOUNT+ " times reflexively with lookup took " + (System.currentTimeMillis( ) - millis) + " millis");

      // Call using a cache of the method.

      md = ri.getClass( ).getMethod("getValue", null);
      millis = System.currentTimeMillis( );
      for (idx = 0; idx < CALL_AMOUNT; idx++) {
        md.invoke(ri, null);
      }
      System.out.println("Calling method " + CALL_AMOUNT + " times reflexively with cache took " + (System.currentTimeMillis( ) - millis) + " millis");

zur Folge haben wird:

[java] Der reflexive Aufruf der Methode 1000000 Mal mit Lookup dauerte 5618 Millis

[java] Der reflexive Aufruf der Methode 1000000 Mal mit Cache hat 270 Millis

0 Stimmen

Die Wiederverwendung von Methoden/Konstruktoren ist in der Tat nützlich und hilfreich, aber beachten Sie, dass der obige Test aufgrund der üblichen Benchmarking-Probleme keine aussagekräftigen Zahlen liefert (keine Aufwärmphase, so dass insbesondere die erste Schleife hauptsächlich die JVM/JIT-Aufwärmzeit misst).

12voto

Mikhail Kraizman Punkte 101

Interessanterweise führt die Einstellung setAccessible(true), die die Sicherheitsprüfungen überspringt, zu einer Verringerung der Kosten um 20 %.

Ohne setAccessible(true)

new A(), 70 ns
A.class.newInstance(), 214 ns
new A(), 84 ns
A.class.newInstance(), 229 ns

Mit setAccessible(true)

new A(), 69 ns
A.class.newInstance(), 159 ns
new A(), 85 ns
A.class.newInstance(), 171 ns

1 Stimmen

Das scheint mir im Prinzip klar zu sein. Werden diese Zahlen linear skaliert, wenn die 1000000 Aufrufen?

0 Stimmen

Eigentlich setAccessible() kann im Allgemeinen viel mehr bewirken, insbesondere bei Methoden mit mehreren Argumenten, weshalb sie immer aufgerufen werden sollte.

8voto

Doradus Punkte 767

Die Reflexion ist langsam, obwohl die Objektzuweisung nicht so hoffnungslos ist wie andere Aspekte der Reflexion. Um eine gleichwertige Leistung mit reflexionsbasierter Instanziierung zu erreichen, müssen Sie Ihren Code so schreiben, dass das Jit erkennen kann, welche Klasse gerade instanziiert wird. Wenn die Identität der Klasse nicht bestimmt werden kann, kann der Zuweisungscode nicht inlined werden. Schlimmer noch, die Escape-Analyse schlägt fehl, und das Objekt kann nicht auf dem Stack zugewiesen werden. Wenn Sie Glück haben, kann das Laufzeit-Profiling der JVM zur Rettung kommen, wenn dieser Code heiß wird, und dynamisch bestimmen, welche Klasse vorherrscht und für diese optimieren.

Seien Sie sich bewusst, dass die Mikrobenchmarks in diesem Thread sehr fehlerhaft sind, nehmen Sie sie also mit Vorsicht zur Kenntnis. Der bei weitem am wenigsten fehlerhafte ist der von Peter Lawrey: Er führt Aufwärmläufe durch, um die Methoden in Gang zu bringen, und er unterläuft (bewusst) die Escape-Analyse, um sicherzustellen, dass die Zuweisungen tatsächlich stattfinden. Aber auch das hat seine Probleme: zum Beispiel kann man davon ausgehen, dass die enorme Anzahl von Array-Speichern Caches und Speicherpuffer aushebelt, so dass dies hauptsächlich ein Speicher-Benchmark sein wird, wenn Ihre Zuweisungen sehr schnell sind. (Hut ab vor Peter, dass er die richtige Schlussfolgerung gezogen hat: dass der Unterschied "150ns" und nicht "2,5x" ist. Ich vermute, dass er so etwas beruflich macht).

7voto

Elie Punkte 13413

Ja, sie ist deutlich langsamer. Wir haben einen Code ausgeführt, der das tat, und obwohl ich die Metriken im Moment nicht zur Hand habe, war das Endergebnis, dass wir den Code so umgestalten mussten, dass er keine Reflektion verwendet. Wenn Sie die Klasse kennen, rufen Sie einfach den Konstruktor direkt auf.

1 Stimmen

+1 Ich habe eine ähnliche Erfahrung gemacht. Es ist gut, darauf zu achten, die Reflexion nur dann zu verwenden, wenn sie absolut notwendig ist.

0 Stimmen

Z.B. benötigen AOP-basierte Bibliotheken Reflexion.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X