Występują pewne dziwne problemy z wydajnością JVM.Dlaczego java.lang.Object.getClass() (i odbicie) jest wolniejszy niż zwykle?
Mamy duży i nieco nieprzejrzysty składnik GUI (Uruchom arkusz kalkulacyjny Formuły 1).
Jeśli zainicjujemy całość z wątku wywołania zdarzenia (tak, jak powinno), stwierdzimy, że kod działa znacznie wolniej (przeciągając mysz, aby wybrać komórki, zauważalne jest opóźnienie).
Jeśli zainicjujemy go po raz pierwszy w głównym wątku programu uruchamiającego, a dopiero potem zaczniemy go używać w EDT, działa znacznie szybciej.
Kiedy patrzę dlaczego wykonuje się powoli za pomocą profilera, wywołania metody, które biorą cały czas są:
- java.lang.Object.getClass()
- java.lang .reflect.Array.newInstance (klasa, int)
- java.lang.Class.getComponentType()
- java.lang.Thread.currentThread()
Jesteśmy przy użyciu 64-bitowego JVM Sun Hotspot w systemie Windows 7 (ten, który jest dostarczany z JDK).
Czy ktokolwiek wie z jakiegokolwiek powodu, dlaczego powyższe metody mogą działać drastycznie wolniej niż zwykle?
Myślę, że może ma to coś wspólnego z porządkiem, w którym klasy są ładowane ... czy to rozsądna teoria? Czy ktoś wie o innych sposobach, w których mogę zdiagnozować, dlaczego wywoływanie tych metod może zająć dużo czasu?
Dołączyłem dwa zrzuty ekranu z profilera. W obu przypadkach wszystko, co robiłem, to przeciąganie myszą wokół komórek arkusza kalkulacyjnego podczas działania profilera. Jest to po prostu aktualizacja komponentu GUI i nie robi się nic więcej.
Pierwszy zajmuje dużo czasu w metodzie zwanej "releaseLock()". Z jakiegoś powodu zajmuje to dużo czasu, ponieważ "getComponentType()" trwa znacznie dłużej niż zwykle.
Drugi jest po zrobiłem „hack”, aby usunąć koszt „releaseLock()” - ale teraz to po prostu spędza dużo czasu w „getLock()” z powodu getClass() i currentThread() przy znacznie dłużej niż normalnie:
Ale ważne jest to, że jeśli po prostu zmienić kolejność, w której kod jest zainicjowany, nic z tego kodu trwa bardzo długo, aby wykonać (nie robi nawet w ogóle nie pojawiają się w profilu).
Jeśli miałem zoptymalizować funkcję getLock(), aplikacja nadal działa znacznie wolniej. Problem polega na tym, że metody takie jak getClass() trwają zbyt długo. Nie ma sposobu, aby to zrekompensować - getClass() zostaje wywołany w zbyt wielu miejscach!
Różnica w wydajności jest zauważalna nawet bez pracy profilera.
Należy pamiętać, że nie możemy zmienić żadnego z tych kodów - jest to składnik zewnętrzny. Wyzwaniem jest wyjaśnienie, dlaczego kod działa o wiele wolniej w pewnych okolicznościach w porównaniu z innymi.
Czy możesz dodać zrzut ekranu profilowania? Ponadto profilowanie może mieć znaczący wpływ na środowisko wykonawcze. Czy możesz wykluczyć te metody z profilowania i sprawdzić, czy istnieją inne powody opóźnienia? – jlordo
Nie wiem, jak wykluczyć te metody z profilowania, ale jak widać, korzysta się z próbkowania i pokazując podział. Myślę, że to, co pokazuje profiler, jest poprawne - nie jest tak, że wykonuje inny kod, po prostu z jakiegoś powodu te wywołania metod, które są zwykle dość niedrogie (Object.getClass()), teraz trwają długo. –
Czy ten wynik jest spójny? Ponieważ jeśli zdarza się to tylko raz, może to być problem z próbkowaniem ("pech" przy wyborze próbki). –