202 Stimmen

Java-Reflexionsleistung

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

4voto

tikoo Punkte 41

In der doReflection() ist der Overhead wegen Class.forName("misc.A") (das würde eine Klassensuche erfordern, die möglicherweise den Klassenpfad im Dateisystem durchsucht), und nicht wegen der newInstance(), die für die Klasse aufgerufen wird. Ich frage mich, wie die Statistik aussehen würde, wenn Class.forName("misc.A") nur einmal außerhalb der for-Schleife ausgeführt wird, da es nicht wirklich bei jedem Aufruf der Schleife ausgeführt werden muss.

1voto

aledbf Punkte 747

Ja, es wird immer langsamer sein, ein Objekt durch Reflexion zu erstellen, weil die JVM den Code nicht zur Kompilierungszeit optimieren kann. Siehe die Sun/Java Tutorials zum Nachdenken für weitere Einzelheiten.

Siehe diesen einfachen Test:

public class TestSpeed {
    public static void main(String[] args) {
        long startTime = System.nanoTime();
        Object instance = new TestSpeed();
        long endTime = System.nanoTime();
        System.out.println(endTime - startTime + "ns");

        startTime = System.nanoTime();
        try {
            Object reflectionInstance = Class.forName("TestSpeed").newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        endTime = System.nanoTime();
        System.out.println(endTime - startTime + "ns");
    }
}

4 Stimmen

Beachten Sie, dass Sie den Lookup ( Class.forName() ) von der Instanziierung (newInstance()) zu unterscheiden, da sie sich in ihren Leistungsmerkmalen erheblich unterscheiden und man in einem gut konzipierten System gelegentlich das wiederholte Nachschlagen vermeiden kann.

4 Stimmen

Außerdem: Sie müssen jede Aufgabe viele, viele Male ausführen, um einen brauchbaren Benchmark zu erhalten: Erstens sind die Aktionen zu langsam, um zuverlässig gemessen zu werden, und zweitens müssen Sie die HotSpot VM aufwärmen, um brauchbare Zahlen zu erhalten.

1voto

sproketboy Punkte 8416

Oft können Sie Apache Commons BeanUtils oder PropertyUtils, die Introspektion (im Grunde sie Zwischenspeicher die Metadaten über die Klassen, so dass sie nicht immer brauchen, um Reflexion zu verwenden) verwenden.

0voto

user_3380739 Punkte 1495

Ich denke, es hängt davon ab, wie leicht/schwer die Ziel-Methode ist. wenn die Ziel-Methode sehr leicht ist (z.B. Getter/Setter), könnte es 1 ~ 3 mal langsamer sein. wenn die Ziel-Methode etwa 1 Millisekunde oder höher dauert, dann wird die Leistung sehr nah sein. hier ist der Test, den ich mit Java 8 und Reflexionsgrad :

public class ReflectionTest extends TestCase {    
    @Test
    public void test_perf() {
        Profiler.run(3, 100000, 3, "m_01 by refelct", () -> Reflection.on(X.class)._new().invoke("m_01")).printResult();    
        Profiler.run(3, 100000, 3, "m_01 direct call", () -> new X().m_01()).printResult();    
        Profiler.run(3, 100000, 3, "m_02 by refelct", () -> Reflection.on(X.class)._new().invoke("m_02")).printResult();    
        Profiler.run(3, 100000, 3, "m_02 direct call", () -> new X().m_02()).printResult();    
        Profiler.run(3, 100000, 3, "m_11 by refelct", () -> Reflection.on(X.class)._new().invoke("m_11")).printResult();    
        Profiler.run(3, 100000, 3, "m_11 direct call", () -> X.m_11()).printResult();    
        Profiler.run(3, 100000, 3, "m_12 by refelct", () -> Reflection.on(X.class)._new().invoke("m_12")).printResult();    
        Profiler.run(3, 100000, 3, "m_12 direct call", () -> X.m_12()).printResult();
    }

    public static class X {
        public long m_01() {
            return m_11();
        }    
        public long m_02() {
            return m_12();
        }    
        public static long m_11() {
            long sum = IntStream.range(0, 10).sum();
            assertEquals(45, sum);
            return sum;
        }    
        public static long m_12() {
            long sum = IntStream.range(0, 10000).sum();
            assertEquals(49995000, sum);
            return sum;
        }
    }
}

Der vollständige Testcode ist auf GitHub verfügbar: ReflectionTest.java

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