Czy powinieneś zminimalizować tworzenie wielu małych obiektów?

10

Pisząc coś, co często tworzy wiele (1000) małych obiektów, powinieneś spróbować zminimalizować to pod kątem wydajności? Zwłaszcza jeśli nie wiesz, na jakim systemie będzie on działał, od niskich do wysokiej klasy komputerów stacjonarnych, a nawet urządzeń mobilnych. W przypadku urządzeń mobilnych słyszałem, że tworzenie wielu obiektów nieco utrudnia wydajność, choć nie wiem, jak to jest prawdziwe.

Mam przykład, który dobrze pokazuje ten pomysł. W programie graficznym powiedzmy, że istnieje metoda, która jest używana do wszystkich idealnie rysowanych rysunków drawPixel(Point). Można utworzyć tysiące punktów i można je często powtarzać, tak jak w grze, w której można je nazwać 60+ razy na sekundę. Alternatywnie drawPixel(int x, int y)można użyć do zminimalizowania tworzenia wielu obiektów Point.

Myślę, że w projektowaniu obiektowym preferowane byłoby używanie Point. Jednak użycie typów pierwotnych może zwiększyć wydajność. W większości przypadków wzrost wydajności może być nieznaczny, ale nie jestem pewien, czy chodzi o urządzenia mobilne czy starsze. Jaki jest wzrost wydajności po zrobieniu czegoś takiego i czy należy to wziąć pod uwagę?

Paski
źródło
Trudno mi znaleźć odniesienia do tego, ale ogólnie w Javie 8 po prostu się o to nie martw. Nie rób oczywiście głupich rzeczy, ale jeśli nie jesteś celowo marnowany, system powinien działać dobrze. Firma Sun / Oracle miała około 20 lat na dostrojenie GC i zarządzania pamięcią i są w tym naprawdę dobrzy.
@ Snowman Słyszałem, że nowsze wersje Java radzą sobie lepiej z zarządzaniem pamięcią, ale widzę problem, ponieważ nie ma gwarancji, że użytkownik nie używa starszej wersji. To część mojego zainteresowania.
Stripies
1
Najpierw wykonaj pomiar wydajności. Jeśli masz jakieś problemy, pomyśl, jak zoptymalizować. Ale proszę nie poświęcać zbyt wcześnie konserwacji kodu, ponieważ uważasz , że możesz mieć problemy z wydajnością.
Zauważył
2
@Stripies Wydajność krótkotrwałych obiektów Java, na które odpowiedziano już w Czy należy unikać tworzenia obiektów w Javie? . Jednak jeśli kiedykolwiek będziesz musiał obsługiwać setki milionów takich obiektów na sekundę, tylko w tym momencie ponownie rozważ ten problem.
rwong
1
Jeśli martwisz się starszymi wersjami Javy, sprawdź to podczas instalacji. JVM wystarczająco stary, aby powodować problemy z zarządzaniem pamięcią, ma również wiele znanych problemów bezpieczeństwa, więc zachęcanie użytkowników do aktualizacji robi im przysługę. System.getProperty("java.version")(lub „java.vm.version”) jest punktem początkowym.
Jerry Coffin

Odpowiedzi:

17

Zasadniczo nie , nie należy unikać tworzenia obiektów z obawy przed utratą wydajności. Jest tego kilka przyczyn.

  1. Korzystanie z obiektów jest swego rodzaju sensem używania Java. Unikanie ich zapobiegawczo jest znakiem, że decyzja o użyciu Java mogła nie być właściwa na początek.
  2. Problemy z wydajnością są niezwykle trudne do przewidzenia. Nigdy nie zakładaj, że coś jest wąskim gardłem. Zawsze mierz. Inżynieria wydajności prawie zawsze polega na wprowadzaniu drobnych zmian we właściwym miejscu. Nie można przewidzieć właściwego miejsca bez pomiaru, tak jak nie można przewidzieć działania leku bez eksperymentu.
  3. Koszt stworzenia obiektu jest znacznie zawyżony. W nowoczesnej maszynie JVM sprowadza się to do zwiększania wskaźnika (a w przypadku generacyjnych śmieciarek koszt zarządzania nią jest również trywialny). W Internecie jest wiele tekstów, które zalecają unikanie obiektów, korzystanie z pulowania obiektów itp. Ta rada była czasem słuszna w latach 90. XX wieku; dziś jest w większości przestarzały. Jest bardzo mało prawdopodobne, aby uzyskać wystarczającą wydajność, aby uzasadnić dodatkowe koszty rozwoju i złożoność wprowadzone przez unikanie Obiektów lub samodzielne zarządzanie nimi.

To powiedziawszy, są miejsca, w których przekształcanie czegoś w obiekt nie ma sensu na początek. Przykładem może być przekazanie dwóch współrzędnych do procedury rysowania: para współrzędnych nie ma niezależnego istnienia, nie ma tożsamości, jest używana tylko raz, a następnie natychmiast odrzucana itp.

Jeśli tak jest, to pewnie, przejdź dalej i podaj dwa ints zamiast zawinąć je w obiekt. OOP nie polega na tym, że wszystko musi być przedmiotem. Chodzi o to, że obiekty ułatwiają tworzenie w miejscach, w których są naturalnym rozwiązaniem problemu reprezentacji danych. Nie unikaj przedmiotów, które mają sens - nie przedstawiaj ich tam, gdzie nie mają sensu.

Kilian Foth
źródło
2

Rozważając wpływ na wydajność przed napisaniem kodu, powinieneś założyć, że nie wiesz, co robisz.

Narzuty na obiekty w Javie w porównaniu do prymitywów są bardzo małe. Im mniejsze obiekty, tym większy będzie odsetek napowietrznych. Jednak już dawno temu nauczyłem się, że rzeczy, które podwajają n, są niczym w porównaniu z rzeczami, które mnożą n przez n.

Tak więc, chociaż tak, możesz dokończyć jakiś system, który miał wpływ o połowę mniejszy lub nawet czwarty, zadaj sobie pytanie, dlaczego tak naprawdę cię to obchodzi. Skomplikowane rozwiązania tego problemu nie zostaną dobrze przyjęte. Zwłaszcza, że ​​nurkowanie w takim kodzie będzie mylące. Zdezorientowani programiści piszą zły kod. Piszą n razy n kod, który powinien być n log n kod. I zajmuje im to więcej czasu.

Teraz, jeśli możesz zaoszczędzić mi miejsce dzięki jakiejś sztuczce, która mieści się w ładnym pudełku, nie muszę zaglądać do środka przez większość czasu, kiedy możemy porozmawiać. Jeśli to pudełko, mogę zamienić je na inne, kiedy to pudełko będzie działać lepiej, mogę nawet za to zapłacić.

candied_orange
źródło
2

W przeprowadzonym dostrajaniu wydajności ( przykład ) zarządzanie pamięcią bardzo łatwo jest głównym winowajcą. Nie obchodzi mnie, jak szalenie dostroili nowego operatora i śmietnik, najszybsze obliczenia nie są obliczeniami. Jeśli więc okaże się, że menedżer pamięci zajmuje sporo czasu i nie mogę uniknąć tworzenia obiektów , to znajduję sposób na ich ponowne użycie, zamiast ciągłego tworzenia nowych.

I tylko to zrobić, jeśli trzeba zrobić obiektów. W przypadku grafiki zazwyczaj nie. IMHO, grafika powinna być rysowana , a nie budowana . Jasne, można powiedzieć, że zdjęcie składa się z punktów, linii, które je łączą, wielokątów, tekstu i tak dalej. To nie znaczy, że nie masz alternatywy do tworzenia z nich przedmiotów przed ich narysowaniem . Po prostu je rysuję.

Istnieje metoda malowania. Przesłoniłem to, narysowałem wszystko do mapy bitowej, a następnie zablokowałem przeniesienie na ekran. Wygląda natychmiastowo. W przypadku wprowadzania za pomocą myszy istnieją metody zastępowania, wykrywania kliknięć, przeciągania i innych czynności.

OOP to dobry pomysł z pewnych powodów. Te powody nie obowiązują we wszystkich sytuacjach.

Mike Dunlavey
źródło
Zgadzam się, ale zgadzam się również ze wszystkimi innymi, że testowanie jest jedynym sposobem, aby się upewnić. Upewnij się, że masz specyfikacje robiące to w prosty / oczywisty sposób przed optymalizacją ... ale zgadzam się, że nowe wciąż mogą stanowić problem.
Bill K
2

Śmiało i używaj małych przydziałów. Nowoczesne menedżery pamięci, szczególnie wysoce zoptymalizowany menedżer obiektów Java, są niezwykle wydajne. Zaoszczędź dużą optymalizację wydajności działającego programu.

Jest bardzo prawdopodobne, że ogólna wydajność będzie wystarczająca. Jeśli okaże się, że tak nie jest, to tylko wtedy profiluj wydajność kodu. Podczas długiej kariery tworzenia oprogramowania nauczyłem się, że wąskie gardła prawie nigdy nie są tam, gdzie się spodziewasz.

Kiedyś członek zespołu spędził kilka dni, dzięki czemu wyszukiwanie członków obiektu było 20 razy szybsze. Sukces! Jednak najlepsze ogólne przyspieszenie w rzeczywistym użyciu zostało zmierzone w setnych procentach. Zmiana została natychmiast wycofana, ponieważ przyspieszenie wymagało większych przydziałów pamięci na element członkowski.

Bill Ferguson
źródło
1

To proste: jeśli potrzebujesz 1000 małych obiektów, możesz utworzyć 1000 małych obiektów i nie martw się o to. Jeśli potrzebujesz 100 małych obiektów, to tworzenie 1000 małych obiektów jest głupie - stwórz te, których potrzebujesz i nie więcej.

Jeśli martwisz się wydajnością (i jeśli nie martwisz się również wydajnością), powinieneś mieć jakąkolwiek funkcjonalność napisaną raz w jednym miejscu, co sprawia, że ​​cały kod jest prostszy i łatwiejszy do zrozumienia. Następnie, jeśli masz problem z wydajnością, pomiary mogą pokazać, że jest jedno miejsce, w którym występuje problem z wydajnością, co ułatwia rzeczy, i tylko jedno miejsce, w którym musisz go zmienić. Albo pomiar pokazuje, że to jedno miejsce nie powoduje żadnych problemów, więc gotowe.

gnasher729
źródło