Java Academy · Oppitunti

Reflectionin suorituskyky ja vaihtoehdot

Mittaa Reflectionin yleiskustannuksia suorien kutsujen vastineena ja tutustu MethodHandles-tyyppiin nopeampana vaihtoehtona.

Oppitunti 4/413 vaihetta

Reflectionin suorituskyky ja vaihtoehdot on ilmainen Java Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Java Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Java Academy-kurssilla on yhteensä 4 oppituntia.

Reflektion aiheuttama kuormitus

Reflektiiviset kutsut ovat huomattavasti hitaampia kuin suorat kutsut: metodin haku sisältää kartan läpikäynnin, tietoturvatarkistuksia ja kääreolioiden luomista. JIT-lämmityksen jälkeen invoke on noin 10–50 kertaa hitaampi kuin suora kutsu.

Reflektion suorituskyvyn mittaaminen

Käyttäkää JMH:ta (Java Microbenchmark Harness) reflektion ja suorien kutsujen aiheuttaman kuormituksen mittaamiseen. Mitatkaa aina todellisessa käyttöyhteydessä — JIT saattaa optimoida osan kuormituksesta pois.

@Benchmark
public String directCall() { return user.getName(); }
@Benchmark
public String reflectiveCall() throws Exception {
    return (String) NAME_METHOD.invoke(user); // NAME_METHOD cached
}

Field- ja Method-olioiden välittäminen

Method- ja Field-olion haku (getDeclaredMethod) on kallein vaihe. Välittäkää tulos static final-kenttään. Välimuistissa olevan olion invoke-kutsu on paljon nopeampi.

public class UserAccessor {
    private static final Method GET_NAME;
    static {
        try {
            GET_NAME = User.class.getDeclaredMethod("getName");
            GET_NAME.setAccessible(true);
        } catch (NoSuchMethodException e) { throw new ExceptionInInitializerError(e); }
    }
    public static String getName(User u) throws Exception { return (String) GET_NAME.invoke(u); }
}

MethodHandles: Lähes suoran kutsun nopeus

MethodHandles.lookup().findVirtual() luo käsittelijän, jonka JIT voi optimoida muutaman kutsun jälkeen lähes suoran kutsun nopeuteen. Se on suositeltava suorituskyvyn kannalta kriittisessä reflektiokoodissa.

MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findVirtual(User.class, "getName",
    MethodType.methodType(String.class));
// Cast to functional interface for max speed:
Function<User, String> getName = user -> {
    try { return (String) mh.invokeExact(user); }
    catch (Throwable t) { throw new RuntimeException(t); }
};

LambdaMetafactory: Paras suorituskyky

LambdaMetafactory luo ajonaikana lambdan MethodHandle-oliosta ja tarjoaa JIT-optimoinnin jälkeen suoran kutsun nopeuden. Jackson ja Kryo käyttävät sitä sisäisesti.

MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findVirtual(User.class, "getName",
    MethodType.methodType(String.class));
CallSite site = LambdaMetafactory.metafactory(lookup, "get",
    MethodType.methodType(Function.class),
    MethodType.methodType(Object.class, Object.class),
    mh, MethodType.methodType(String.class, User.class));
Function<User, String> fn = (Function<User, String>) site.getTarget().invokeExact();
System.out.println(fn.apply(user));

Käännösaikainen koodigenerointi APT:llä

Annotaatioprosessorit luovat lähdetiedostoja käännösaikana. Lombokin ja MapStructin kaltaiset kehykset käyttävät APT:tä tyyppiturvallisen ja täysin reflektiottoman boilerplate-koodin tuottamiseen — näin ajonaikainen suorituskyky on paras mahdollinen.

Byte Buddy ajonaikaiseen koodigenerointiin

Byte Buddy luo aliluokkia ja välityspalvelimia ajonaikana tavukoodia muokkaamalla. Se on suorituskyvyn kannalta kriittisissä kohdissa paljon dynaamisia välityspalvelimia nopeampi. Sitä käyttävät muun muassa Mockito, Hibernate ja ByteCodeLib.

// Byte Buddy example — create a class with a method:
Class<?> dynamicType = new ByteBuddy()
    .subclass(Object.class)
    .method(ElementMatchers.named("toString"))
    .intercept(FixedValue.value("Hello Byte Buddy!"))
    .make()
    .load(getClass().getClassLoader())
    .getLoaded();
System.out.println(dynamicType.newInstance()); // Hello Byte Buddy!

Reflektion välttäminen suorituskyvyn kannalta kriittisissä kohdissa

Käyttäkää reflektiota kehyksen alustamiseen eli käynnistysaikana, älkää pyyntökohtaisissa suorituspoluissa. Siirtäkää reflektiota käyttävä työ sovelluksen käynnistykseen ja välittäkää kaikki mahdollinen aggressiivisesti.

Moduulijärjestelmä ja reflektio (Java 9+)

Java 9:n ja sitä uudempien versioiden moduulit estävät syvän reflektion oletusarvoisesti. Myöntäkää käyttöoikeus --add-opens-valitsimella tai module-info.java opens-direktiiveillä. Kirjastot käyttävät yhä useammin MethodHandles-ratkaisua välttääkseen --add-opens-valitsimen tarpeen.

// module-info.java:
module com.example.app {
    opens com.example.model to com.example.framework; // allow reflective access
}

Reflektion ja koodigeneroinnin kompromissit

Reflektio on yksinkertaista ja joustavaa, mutta hidasta. Koodigenerointi (APT/Byte Buddy) on nopeaa ja tyyppiturvallista, mutta sen käyttöönotto on monimutkaista. Valitkaa lähestymistapa sen perusteella, tapahtuuko työ käynnistysaikana (reflektio sopii) vai pyyntöaikana (välttäkää reflektiota).

Reflektion käytön profilointi

Käyttäkää JFR:ää (Java Flight Recorder) tai async-profileria selvittääksenne, missä reflektion aiheuttama kuormitus kertyy. Etsikää sun.reflect.*- tai java.lang.reflect.*-kohtia kuumien metodien luettelosta.

Pikatarkistus

Mikä on nopein ajonaikainen vaihtoehto Method.invoke-metodille suorituskyvyn kannalta kriittisissä reflektiivisissä kutsuissa?

Kertaus

Välittäkää Method- ja Field-oliot haun aiheuttaman kustannuksen vähentämiseksi. Käyttäkää MethodHandles-ratkaisua suorituskyvyn kannalta kriittisissä kohdissa. Käyttäkää LambdaMetafactory-ratkaisua parhaan suorituskyvyn saavuttamiseksi. Käyttäkää APT:tä tai Byte Buddya reflektion poistamiseen kokonaan kriittisistä osioista.

Aloita maksutta

Opi Java tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
104
Oppitunnit
374

Usein kysytyt kysymykset

Onko oppitunti ”Reflectionin suorituskyky ja vaihtoehdot” ilmainen?

Kyllä – oppitunnin ”Reflectionin suorituskyky ja vaihtoehdot” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Java Academy-kurssin, päivitä CoddyKit PROhon. Java Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Reflectionin suorituskyky ja vaihtoehdot”?

Mittaa Reflectionin yleiskustannuksia suorien kutsujen vastineena ja tutustu MethodHandles-tyyppiin nopeampana vaihtoehtona. Harjoittelet Java Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Java Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Java Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.

Kuinka kauan ”Reflectionin suorituskyky ja vaihtoehdot”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Java Academy-oppitunnilla?

Kyllä. Jokainen Java Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Luokkien tarkastelu Reflectionilla
  2. Metodien kutsuminen ja kenttien käyttäminen
  3. Dynaamiset proxyt InvocationHandlerilla
  4. Reflectionin suorituskyky ja vaihtoehdot
← Takaisin: Java Academy