Wąskie Gardło Alokacji Pamięci/Dealokacji?

Jak dużym wąskim gardłem jest alokacja/dealokacja pamięci w typowych programach w świecie rzeczywistym? Mile widziane są odpowiedzi z każdego rodzaju programu, w którym wydajność zazwyczaj ma znaczenie. Czy przyzwoite implementacje malloc / free / garbage collection są na tyle szybkie, że jest to tylko wąskie gardło w kilku narożnych przypadkach, czy też większość oprogramowania o krytycznym znaczeniu odniosłaby znaczne korzyści z prób utrzymania ilości alokacji pamięci w dół lub szybszego malloc/free / garbage collection wdrożenie?

Uwaga: ja NIE mówię tutaj o rzeczach w czasie rzeczywistym. Mówiąc o wydajności, mam na myśli rzeczy, w których przepustowość ma znaczenie, ale opóźnienia niekoniecznie.

Edit: chociaż wspominam malloc, to pytanie jest NIE przeznaczone do C/C++ specyficzne.

Author: EmeryBerger, 2009-01-22

12 answers

Jest to znaczące, zwłaszcza, że rozdrobnienie rośnie i alokator musi mocniej polować na większe hałdy dla sąsiednich regionów, o które prosisz. Większość aplikacji wrażliwych na wydajność zazwyczaj pisze własne alokatory bloków o stałej wielkości (np. proszą SYSTEM OPERACYJNY o pamięć 16 MB na raz, a następnie przesyłają ją w stałych blokach 4kb, 16KB itp.), aby uniknąć tego problemu.

W grach widziałem połączenia do malloc () / free () zużywają aż 15% CPU( w słabo napisanych produktach), lub dzięki starannie napisanym i zoptymalizowanym alokatorom bloków, zaledwie 5%. Biorąc pod uwagę, że gra musi mieć stałą przepustowość sześćdziesięciu herców, posiadanie jej na 500ms, podczas gdy od czasu do czasu działa garbage collector, nie jest praktyczne.

 35
Author: Crashworks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-22 20:41:25

Prawie każda wysokowydajna aplikacja musi teraz używać wątków do wykorzystania obliczeń równoległych. To jest, gdzie prawdziwy zabójca prędkości alokacji pamięci przychodzi podczas pisania aplikacji C / C++.

W aplikacji C lub c++, malloc / new musi zablokować globalną stertę dla każdej operacji. Nawet bez zastrzeżeń zamki są dalekie od wolności i należy ich unikać w miarę możliwości.

Java i C# są w tym lepsze, ponieważ threading został zaprojektowany od początku i alokatory pamięci działają z puli poszczególnych wątków. Można to zrobić również w C / C++, ale nie jest to automatyczne.

 20
Author: Zan Lynx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-22 20:49:11

Po pierwsze, skoro powiedziałeś malloc, zakładam, że mówisz o C lub c++.

Alokacja pamięci i dealokacja wydają się być znaczącym wąskim gardłem dla rzeczywistych programów. Wiele dzieje się "pod maską" podczas przydzielania lub dealokacji pamięci, a wszystko to jest specyficzne dla systemu; pamięć może być faktycznie przenoszona lub defragmentowana, strony mogą być reorganizowane--nie ma niezależnego od platformy sposobu, aby wiedzieć, jaki będzie wpływ. Niektóre systemy (jak wiele konsol do gier) również nie robią defragmentacja pamięci, więc na tych systemach zaczniesz usuwać błędy z pamięci, gdy pamięć stanie się fragmentaryczna.

Typowym obejściem jest przydzielenie jak największej ilości pamięci z przodu i wstrzymanie jej do momentu zakończenia programu. Możesz użyć tej pamięci do przechowywania dużych, monolitycznych zestawów danych lub użyć implementacji puli pamięci do przechowywania jej w kawałkach. Wiele implementacji bibliotek standardowych C / C++ wykonuje pewną ilość pamięci w celu powód.

Nie ma na to dwóch sposobów--jeśli masz czasochłonny program C / C++, Robienie dużej alokacji / dealokacji pamięci zabije wydajność.

 11
Author: MattK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-22 20:47:19

Ogólnie koszt alokacji pamięci jest prawdopodobnie przyćmiony przez blokadę, złożoność algorytmu lub inne problemy z wydajnością w większości aplikacji. Ogólnie rzecz biorąc, powiedziałbym, że prawdopodobnie nie jest to pierwsza dziesiątka problemów z wydajnością, o które bym się martwił.

Teraz, przechwytywanie bardzo dużych kawałków pamięci może być problemem. A chwytanie, ale nie właściwe pozbycie się pamięci, to coś, o co bym się martwił.

W językach Java i JVM nowe obiekty są teraz bardzo, bardzo, bardzo szybko.

Oto jeden przyzwoity artykuł faceta, który zna się na rzeczy z pewnymi odniesieniami na dole do bardziej powiązanych linków: http://www.ibm.com/developerworks/java/library/j-jtp09275.html

 7
Author: Alex Miller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-22 20:42:05

W Javie (i potencjalnie innych językach z przyzwoitą implementacją GC) przydzielanie obiektu jest bardzo tanie. W słońcu JVM potrzebuje tylko 10 cykli procesora. Malloc w C / C++ jest znacznie droższy, tylko dlatego, że musi wykonać więcej pracy.

Mimo to nawet alokacja obiektów w Javie jest bardzo tania, co dla wielu użytkowników aplikacji webowej może prowadzić do problemów z wydajnością, ponieważ uruchamiane będą kolejne uruchamianie Garbage Collector. Są więc takie pośrednie koszty alokacji w Javie spowodowane dealokacją dokonaną przez GC. Koszty te są trudne do oszacowania, ponieważ w dużym stopniu zależą od konfiguracji (ile pamięci masz) i aplikacji.

 5
Author: kohlerm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-25 18:38:58

Maszyna wirtualna Java będzie odbierać i zwalniać pamięć z systemu operacyjnego praktycznie niezależnie od tego, co robi kod aplikacji. Pozwala to na przechwytywanie i zwalnianie pamięci w dużych kawałkach, co jest znacznie bardziej wydajne niż robienie tego w małych indywidualnych operacjach, jak w przypadku ręcznego zarządzania pamięcią.

Ten artykuł został napisany w 2005 roku, a zarządzanie pamięcią w stylu JVM było już dostępne. Od tego czasu sytuacja uległa jedynie poprawie.

Które język oferuje szybsze raw wydajność alokacji, Java język, czy C / C++? Odpowiedź może zaskoczyć Cię-przydział w nowoczesnej JVMs jest znacznie szybszy niż najlepszy wykonywanie wdrożeń malloc. Na wspólna ścieżka kodu dla nowego obiektu () w HotSpot 1.4.2 i nowsze to około 10 instrukcji maszynowych (dane dostarczone przez Sun; patrz zasoby), najlepszy malloc wdrożenia w C wymagają na średnio od 60 do 100 instrukcje na wywołanie (Detlefs, et. al.; patrz zasoby). I przydział wydajność nie jest błahym składnikiem ogólnej wydajności -- benchmarki pokaż, że wiele realnych C i C++ programów, takich jak Perl i Ghostscript, wydaj od 20 do 30 procent całkowity czas realizacji w malloc i wolny-znacznie więcej niż przydział i wywóz śmieci nad głową zdrowej Javy podanie.

 4
Author: skaffman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-06 09:23:58

Przydzielanie i zwalnianie pamięci pod względem wydajności to stosunkowo kosztowne operacje. Wywołania w nowoczesnych systemach operacyjnych muszą iść aż do jądra, tak aby system operacyjny był w stanie poradzić sobie z pamięcią wirtualną, stronicowaniem/mapowaniem, ochroną wykonania itp.

Z drugiej strony, prawie wszystkie nowoczesne języki programowania ukrywają te operacje za "alokatorami", które działają z wstępnie przydzielonymi buforami.

Pojęcie to jest również używane przez większość aplikacji które koncentrują się na przepustowości.

 3
Author: Kosi2801,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-01-22 20:44:16

Wiem, że odpowiedziałem wcześniej, jednak to była odpowiedź na drugą odpowiedź, nie na twoje pytanie.

Mówiąc wprost, jeśli dobrze rozumiem, Twoje kryteria zastosowania wydajności to przepustowość.

To dla mnie oznacza, że powinieneś patrzeć niemal wyłącznie na NUMA aware alokatory .

Brak wcześniejszych odniesień; IBM JVM paper, Microquill C, SUN JVM. Zakryj ten punkt, więc jestem wysoce podejrzany o ich zastosowanie dzisiaj, gdzie przynajmniej na AMD ABI, NUMA jest wybitnym regulatorem pamięci-procesora.

Ręce w dół; realny świat, fałszywy świat, jakikolwiek świat... NUMA aware pamięci żądanie / wykorzystanie technologii są szybsze. Niestety, obecnie używam systemu Windows i nie znalazłem "numastat", który jest dostępny w Linuksie.

A mój przyjaciel napisał o tym w swojej implementacji jądra FreeBSD.

Dispite me being able to show at-hoc, zazwyczaj bardzo duża ilość żądań pamięci węzłów lokalnych na szczycie zdalnego węzła (podkreślając oczywistą wydajność przepustowość przewaga), można gburowaty benchmark siebie, i to prawdopodobnie jest to, co trzeba todo jak charicterisitc wydajność będzie bardzo specyficzne.

Wiem to na wiele sposobów, przynajmniej wcześniej 5.x VMWARE wypadł raczej słabo, przynajmniej w tym czasie, bo nie korzystał z NUMA, często wymagających stron z odległego węzła. Maszyny wirtualne są jednak wyjątkową bestią, jeśli chodzi o dzielenie pamięci lub konteneryzację.

Jednym z odniesień, które przytoczyłem, jest zaimplementowanie API Microsoftu dla AMD ABI, które ma NUMA alokacji wyspecjalizowanych interfejsów dla programistów land aplikacji do wykorzystania;)

Oto dość niedawna analiza , wizualna i w ogóle, od niektórych programistów dodatków do przeglądarek, którzy porównują 4 różne implementacje sterty. Naturalnie ten, który opracowany okazuje się na szczycie (dziwne, jak ludzie, którzy robią testy często wykazują najwyższy wynik).

One pokrywają w pewien sposób ilościowo, przynajmniej dla ich przypadku użycia, co dokładnie kompromis jest między przestrzenią / czasem, ogólnie zidentyfikowali LFH (oh ya i przy okazji LFH jest po prostu tryb pozornie standardowe sterty) lub podobnie zaprojektowane podejście zasadniczo zużywa znacznie więcej pamięci od nietoperza jednak w czasie, może skończyć się przy użyciu mniej pamięci... grafix też jest fajny...

Myślę jednak, że wybranie implmentacji stosu na podstawie typowego obciążenia pracą po tym, jak dobrze ją zrozumiesz;) jest dobrym pomysłem, ale aby dobrze zrozumieć swoje potrzeby, najpierw upewnij się, że podstawowe operacje są poprawne, zanim zoptymalizujesz te szanse i końce;)

 3
Author: RandomNickName42,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-06 09:01:27

Tutaj najlepiej sprawdza się system alokacji pamięci c / C++. Domyślna strategia alokacji jest w porządku w większości przypadków, ale można ją zmienić w zależności od potrzeb. W GC systems niewiele można zrobić, aby zmienić strategie alokacji. Oczywiście istnieje cena do zapłacenia, a to jest potrzeba śledzenia alokacji i ich prawidłowego uwolnienia. C++ posuwa to dalej i strategia alokacji może być określona dla klasy przy użyciu nowego operatora:

class AClass
{
public:
  void *operator new (size_t size); // this will be called whenever there's a new AClass
   void *operator new [] (size_t size); // this will be called whenever there's a new AClass []
  void operator delete (void *memory); // if you define new, you really need to define delete as well
  void operator delete [] (void *memory);define delete as well
};

Wiele szablonów STL umożliwia również definiowanie własnych alokatorów.

Podobnie jak w przypadku wszystkich kwestii związanych z optymalizacją, przed napisaniem własnych alokatorów należy najpierw określić, poprzez analizę czasu pracy, czy alokacja pamięci naprawdę jest wąskim gardłem.

 3
Author: Skizz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-03 14:31:25

Zgodnie z MicroQuill SmartHeap Specyfikacja techniczna, " typowe zastosowanie [...] spędza 40% całkowitego czasu wykonania na zarządzanie pamięcią". Możesz wziąć tę liczbę jako górną granicę, osobiście uważam, że typowa aplikacja spędza więcej niż 10-15% czasu wykonania alokując / dealokując pamięć. Rzadko jest wąskim gardłem w aplikacji jednowątkowej.

W wielowątkowych aplikacjach C / C++ standardowe alokatory stają się problemem ze względu na blokadę. To to miejsce, w którym zaczynasz szukać bardziej skalowalnych rozwiązań. Ale pamiętaj prawo Amdahla .

 2
Author: Constantin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-02 09:08:46

Inni zajmowali się C / C++ więc dodam trochę informacji na .NET.

W. NET heap alokacja jest na ogół bardzo szybka, ponieważ jest to tylko kwestia przechwycenia pamięci w części Generation zero sterty. Oczywiście to nie może trwać wiecznie, i tu pojawia się śmieciarka. Usuwanie śmieci może znacząco wpłynąć na wydajność aplikacji, ponieważ wątki użytkownika muszą być zawieszone podczas zagęszczania pamięci. Im mniej pełnych zbiorów, tym lepiej.

Są różne rzeczy, które możesz zrobić, aby wpłynąć na obciążenie garbage collector w .NET. generalnie, jeśli masz dużo pamięci odniesienia, garbage collector będzie musiał zrobić więcej pracy. Np. poprzez implementację wykresu przy użyciu macierzy przylegania zamiast odniesień między węzłami, garbage collector będzie musiał analizować mniej odniesień.

To, czy jest to rzeczywiście istotne w aplikacji, czy nie, zależy od kilku czynników i należy profilować aplikację z rzeczywistymi danymi przed przejściem do takich optymalizacji.

 1
Author: Brian Rasmussen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-02 09:31:12

Prawie wszyscy z was są poza bazą, jeśli mówimy o stercie Microsoftu. Synchronizacja odbywa się bez wysiłku, podobnie jak fragmentacja.

Bieżąca perferrred heap jest LFH, (niski fragmentacja sterta), jest domyślna w systemie vista + OS i może być skonfigurowana NA XP, poprzez gflag, bez większych problemów

Łatwo jest uniknąć problemów z blokowaniem / blokowaniem/niezgodnością / bus-bandwitth i partii z

HEAP_NO_SERIALIZE

Opcja podczas HeapAlloc lub HeapCreate. Pozwoli to na utworzenie / użycie sterty bez wchodzenia w blokowane oczekiwanie.

Polecam tworzenie kilku stosów, z HeapCreate i definiowanie makra, być może mallocx (enum my_heaps_set, size_t);

Byłoby w porządku, oczywiście, potrzebujesz realloc, free również być skonfigurowany jako appropiate. Jeśli chcesz uzyskać fantazję, wykonaj free / realloc automatyczne wykrywanie, które sterty obsługują samodzielnie, oceniając adres wskaźnika, lub nawet dodając logikę do pozwól mallocowi zidentyfikować, której sterty użyć na podstawie identyfikatora wątku i zbuduj heierarchię stosów dla wątków i współdzielonych globalnych Stert/pul.

API sterty * są wywoływane wewnętrznie przez malloc / new.

Oto fajny artykuł na temat dynamicznych problemów z zarządzaniem pamięcią , Z jeszcze ładniejszymi odniesieniami. Do instrumentowania i analizowania aktywności sterty.

 1
Author: RandomNickName42,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-02 11:27:36