2010-10-25 20 views
42

Istnieje wiele wskazówek dotyczących wydajności, które zostały przestarzałe przez kompilator Java, a zwłaszcza Profile-guided optimization. Na przykład te optymalizacje dostarczane przez platformę mogą drastycznie (według źródeł) zmniejszyć koszt wywołań funkcji wirtualnych. VM jest również zdolny do inlineowania metod, rozwijania pętli itp.Przestarzałe wskazówki dotyczące optymalizacji Java

Jakie inne techniki optymalizacji wydajności pojawiły się w dalszym ciągu stosowane, ale są faktycznie przestarzałe przez mechanizmy optymalizacji znalezione w bardziej nowoczesnych maszynach JVM?

+0

Mam nagrodę za pokrewne pytanie tutaj, jeśli ktoś ma cytaty na odpowiedzi na to: http://stackoverflow.com/questions/3963643/canonical-reference-on -jvm-internals-for-programmer-developers – andersoj

+0

Wpadłem na pytanie, które jest wadliwe, ponieważ zależy od używanego kompilatora. –

+0

Nie jest wadliwe, tylko "szerokie". –

Odpowiedz

23

Ostateczny modyfikator metod i parametrów metod nie pomaga w ogóle w wydajności.

Ponadto, Java HotSpot wiki daje dobry przegląd optymalizacji używanych przez HotSpot i jak skutecznie używać ich w kodzie Java.

+2

ładny link, ale nie wydaje się, że odrzuca "final". Mówi, że "końcowy" jest wskazówką do inline. Sądziłem, że są przypadki, w których ostateczny modyfikator zapewni kompilatorowi, że jego wartość nie może się zmienić w pętli, nawet jeśli ta pętla wywołuje inne metody i poza bieżący horyzont. – Will

+0

Zobacz: http://stackoverflow.com/questions/3961881/why-defining-class-as-final-improves-jvm-performance – andersoj

+4

'final' na temat metod (lub klas w tym zakresie) nie dostarcza informacji do JIT. Jednak "final" parametru parametru może bardzo dobrze dostarczyć użytecznych wskazówek optymalizacyjnych (podobnie jak zmienna lokalna zadeklarowana jako ostateczna). Ostatecznie jednak ostatecznym celem jest wymuszenie niezmienności - jest to cecha charakterystyczna dla projektowania, która ułatwia kodowanie. Każda korzyść z optymalizacji musiałaby być a) martwa tylko o to, czy rzeczywiście wystąpił problem z wydajnością, oraz b) przetestowane w sposób wyczerpujący, aby upewnić się, że rzeczywiście miało to wpływ. –

20

Osoby zastępujące String a = "this" + var1 + " is " + var2; z wieloma połączeniami do StringBuilder lub StringBuffer. W rzeczywistości używa już StringBuilder za kulisami.

+0

W tym przypadku I że optymalizacja nadal obowiązuje. Przykładowy kod, który pokazano, tworzyłby 3 odrębne instancje StringBuilder, po jednym dla każdej konkatenacji; zbudowanie tylko jednego byłoby (nieco) bardziej wydajne. Popraw mnie, jeśli się mylę. – RMorrisey

+3

Och, myślałem, że będzie to odpowiednik 'String a = new StringBuilder (" this ") .endend (var1) .append (" jest ") .endend (var2) .toString();'? –

+3

to * niedozwolone * źródło http://www.rgagnon.com/javadetails/java-0129.html sugeruje, że Paul ma rację odnośnie pojedynczego StringBuildera, ale mówi, że domyślna pojemność StringBuilder może być zbyt krótka (dziwne, byłoby to trywialne, gdyby kompilator, który potrzebował czasu na użycie StringBuffer, nie zechciałby zliczyć pojemności przed użyciem) – Will

8

W 2001 r. Zrobiłem aplikacje na telefon J2ME. Był wielkości cegły. I prawie prawie moc obliczeniowa cegły.

Uruchamianie aplikacji Java na żądanie wymagało zapisania ich w sposób możliwie jak najbardziej proceduralny. Ponadto bardzo dużą poprawą wydajności było złapanie ArrayIndexOutOfBoundsException, aby opuścić pętle for we wszystkich elementach w wektorze. Pomyśl o tym!

Nawet na Androidzie są "szybkie" pętle przez wszystkie elementy w tablicy i "powolne" sposoby pisania tego samego, jak wspomniano w filmach Google IO na temat urządzeń wewnętrznych dalvik VM.

Jednakże, w odpowiedzi na twoje pytanie, powiedziałbym, że najbardziej niezwykłe jest mikro-optymalizacja tego typu rzeczy w dzisiejszych czasach, a ponadto oczekiwałbym, że na maszynie wirtualnej JIT (nawet nowy Android 2.2 VM, która dodaje JIT) te optymizacje są dyskusyjne. W 2001 roku telefon uruchomił interpreter KVM na częstotliwości 33 MHz. Teraz uruchamia dalvik - o wiele szybszą maszynę wirtualną niż KVM - od 500 MHz do 1500 MHz, ze znacznie szybszą architekturą ARM (lepszy procesor, nawet pozwalający na zwiększenie prędkości zegara) z L1 e.t.c. i JIT przybywa.

Nie jesteśmy jeszcze w królestwie, w którym byłoby mi wygodnie robić bezpośrednie manipulacje pikselami w Javie - zarówno w telefonie, jak i na komputerze stacjonarnym z i7 - więc nadal istnieje normalny codzienny kod, którego Java nie jest wystarczająco szybko dla. Here's an interesting blog który twierdzi, że ekspert powiedział, że Java jest 80% prędkości C++ dla niektórych ciężkich zadań CPU; Jestem sceptyczny, piszę kod manipulacji obrazem i widzę rząd wielkości pomiędzy Javą i natywną dla pętli ponad pikselami. Może brakuje mi jakiejś sztuczki ...? : D

+1

Trochę OT, ale jeśli chodzi o wydajność, mój przyjaciel stworzył źródłowy wierny port doomów w Javie, a osiąga około 130-145 klatek na sekundę przy rozdzielczości 640x480 na jednym gwintowanym P4 @ 3GHz. Nie OpenGL, tylko blitting. –

+0

Tak, ale grałem Doom akceptowalnie na 486 ... (jednak projekt twojego przyjaciela brzmi bardzo fajnie i bardzo fajnie) – Will

16

Konieczne jest zdefiniowanie kompromisów czas/pamięć przed rozpoczęciem optymalizacji wydajności. Oto jak to zrobić dla mojej pamięci/aplikacji krytycznym momencie (powtarzając kilka odpowiedzi powyżej, aby być kompletna):

  1. Zasada # 1 Nigdy nie rób optymalizacji wydajności na wcześniejszym etapie rozwoju. Nigdy tego nie rób, jeśli naprawdę tego nie potrzebujesz. Jeśli zdecydujesz się to zrobić, to:
  2. użyj profilera, aby znaleźć wąskie gardła, sprawdź kod źródłowy, aby znaleźć przyczyny wąskich gardeł;
  3. wybierz odpowiednią strukturę danych z najlepszym dopasowaniem do zdefiniowanych kompromisów czas/pamięć;
  4. wybierz odpowiednie algorytmy (np.iteracja vs rekursja, itp);
  5. unikaj używania zsynchronizowanych obiektów z biblioteki Java, jeśli naprawdę tego nie potrzebujesz;
  6. unikać jawnie/niejawnie tworzenia nowych obiektów;
  7. zastępuje/ponownie implementuje typy danych/algorytmy przychodzące z java wtedy i tylko wtedy, gdy masz pewność, że nie spełniają Twoich wymagań.
  8. Użyj małych, niezależnych testów, aby przetestować wydajność wybranych struktur algos/danych.
+2

Te wskazówki nie są naprawdę obselete. Mam na myśli, to świetna rada, ale nie odpowiadasz na pytanie. –

+2

-1: brak odpowiedzi na pytanie. –

1
  1. "Przedwczesna optymalizacja jest źródłem wszelkiego zła" (Donald Knuth)
  2. Jest to przydatne w celu optymalizacji tylko wąskie gardła.
  3. Należy przeanalizować kod w każdej sytuacji. Być może możesz zastąpić TreeSet szybkim HashSet, ponieważ nie potrzebujesz funkcji sortowania lub możesz użyć float zamiast double (spójrz na SDK Androida).
  4. Jeśli żadna technika nie pomoże, możesz spróbować przepisać fragment kodu i zadzwonić pod numer JNI, aby działał natywny kod.
+6

-1 dla oferty, która jest zarówno niekompletna, jak i nieistotna dla pytania. Donald Knuth powiedział: "Powinniśmy zapomnieć o małych wydajnościach, powiedzmy o 97% przypadków: przedwczesna optymalizacja jest źródłem wszelkiego zła" Po drugie, pytanie dotyczy ogólnych technik optymalizacji, które nie mają już zastosowania, nie ma nic, co mogłoby wykazać, że jest przedwczesne, to ogólna dyskusja – hhafez

4
  1. Nie ręcznie wywołać śmieciarza, boli wydajność nowoczesnych implementacji JVM.
  2. Liczba całkowita zamiast długa nie pozwoli zaoszczędzić dużo miejsca, ale ograniczy zakres liczb.
  3. Unikaj generowanych ręcznie klas Enum i korzystaj z wbudowanej funkcji Enum. Java 1.5 wprowadziła prawdziwe Enums, używaj ich.
2

Przy użyciu x64 JVM z pamięcią RAM mniej niż 32 GB:

64-JVM stosowanie 30% -50% więcej pamięci Porównanie z 32-bitowy JVM powodu większych zwykłe wskaźniki obiektów. Możesz znacznie zmniejszyć ten współczynnik, używając JDK6 +.

Od JDK6u6p do JDK6u22 jest opcjonalny i może być włączony przez dodanie argumentu JVM:

-XX:+UseCompressedOops 

Od JDK6u23 (JDK7 również) jest domyślnie włączona. Więcej informacji here.

Powiązane problemy