Istnieje wiele metod, aby przydzielić pamięci w środowisku Windows, takie jak VirtualAlloc
, HeapAlloc
, malloc
, new
.
Jaka jest więc różnica między nimi?
źródło
Istnieje wiele metod, aby przydzielić pamięci w środowisku Windows, takie jak VirtualAlloc
, HeapAlloc
, malloc
, new
.
Jaka jest więc różnica między nimi?
Każdy interfejs API jest przeznaczony do różnych zastosowań. Każdy z nich wymaga również użycia prawidłowej funkcji zwalniania / zwalniania, gdy skończysz z pamięcią.
Niskopoziomowy interfejs API systemu Windows, który zapewnia wiele opcji, ale jest przydatny głównie dla osób w dość specyficznych sytuacjach. Można przydzielić pamięć tylko w (edytuj: nie 4KB) większych fragmentach. Są sytuacje, w których tego potrzebujesz, ale będziesz wiedział, że jesteś w jednej z takich sytuacji. Jednym z najczęstszych jest udostępnianie pamięci bezpośrednio innemu procesowi. Nie używaj go do alokacji pamięci ogólnego przeznaczenia. Służy VirtualFree
do zwalniania przydziału.
Alokuje pamięć o dowolnej wielkości, a nie w dużych porcjach VirtualAlloc
. HeapAlloc
wie, kiedy musi zadzwonić, VirtualAlloc
i robi to automatycznie. Podobnie jak malloc
, ale jest tylko dla systemu Windows i zapewnia kilka dodatkowych opcji. Nadaje się do przydzielania ogólnych fragmentów pamięci. Niektóre interfejsy API systemu Windows mogą wymagać użycia tej funkcji w celu przydzielenia przekazywanej im pamięci lub użycia jej elementu towarzyszącego w HeapFree
celu zwolnienia pamięci, którą zwracają.
Sposób przydzielania pamięci w języku C. Preferuj to, jeśli piszesz w C, a nie C ++ i chcesz, aby Twój kod działał np. Również na komputerach z systemem Unix lub ktoś konkretnie mówi, że musisz go używać. Nie inicjalizuje pamięci. Nadaje się do przydzielania ogólnych fragmentów pamięci, takich jak HeapAlloc
. Prosty interfejs API. Służy free
do zwalniania przydziału. malloc
Wywołania Visual C ++ HeapAlloc
.
Sposób przydzielania pamięci w języku C ++. Wolisz to, jeśli piszesz w C ++. Umieszcza również obiekt lub obiekty w przydzielonej pamięci. Służy delete
do zwalniania alokacji (lub delete[]
dla tablic). Visual Studio new
wywołuje HeapAlloc
, a następnie może inicjalizuje obiekty, w zależności od tego, jak to nazwiesz.
W najnowszych standardach C ++ (C ++ 11 i nowszych), jeśli musisz ręcznie używać delete
, robisz to źle i zamiast tego powinieneś użyć inteligentnego wskaźnika, takiego jak unique_ptr
. Począwszy od C ++ 14 można to samo powiedzieć new
(zastąpione funkcjami takimi jak make_unique()
).
Istnieje również kilka innych podobnych funkcji, takich jak SysAllocString
ta, z której możesz zostać poinformowany, że musisz użyć w określonych okolicznościach.
Bardzo ważne jest, aby zrozumieć różnicę między interfejsami API alokacji pamięci (w systemie Windows), jeśli planujesz używać języka wymagającego zarządzania pamięcią (takiego jak C lub C ++). Najlepszym sposobem zilustrowania tego IMHO jest diagram:
Zauważ, że jest to bardzo uproszczony widok specyficzny dla systemu Windows.
Sposobem na zrozumienie tego diagramu jest to, że im wyżej na diagramie znajduje się metoda alokacji pamięci, tym wyższy poziom używa jej implementacji. Ale zacznijmy od dołu.
Menedżer pamięci trybu jądra
Zapewnia wszystkie rezerwacje i alokacji pamięci dla systemu operacyjnego, jak również wsparcie dla plików pamięci odwzorowany , współdzielonej pamięci , kopiowanie przy zapisie operacji, itd. To nie jest dostępny bezpośrednio z kodu trybu użytkownika, więc pominę to tutaj.
VirtualAlloc / VirtualFree
Są to interfejsy API najniższego poziomu dostępne w trybie użytkownika .
VirtualAlloc
Funkcja zasadzie wywołuje ZwAllocateVirtualMemory który z kolei dokonuje szybkiej syscall sięring0
do dalszego przetwarzania spycha do menedżera pamięci jądra. Jest to również najszybsza metoda rezerwacji / alokacji bloku nowej pamięci spośród wszystkich dostępnych w trybie użytkownika.Ale ma dwa główne warunki:
Przydziela tylko bloki pamięci wyrównane na granicy szczegółowości systemu.
Przydziela tylko bloki pamięci o rozmiarze będącym wielokrotnością ziarnistości systemu.
Jaka jest więc szczegółowość systemu ? Możesz to uzyskać, wywołując GetSystemInfo . Jest zwracany jako
dwAllocationGranularity
parametr. Jego wartość jest specyficzna dla implementacji (i prawdopodobnie sprzętu), ale w wielu 64-bitowych systemach Windows jest ustawiana na0x10000
bajty lub64K
.To wszystko oznacza, że jeśli spróbujesz przydzielić, powiedz tylko 8-bajtowy blok pamięci z
VirtualAlloc
:void* pAddress = VirtualAlloc(NULL, 8, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
Jeśli się powiedzie,
pAddress
zostanie wyrównany na0x10000
granicy bajtów. I nawet jeśli zażądałeś tylko 8 bajtów, rzeczywisty blok pamięci, który otrzymasz, będzie całympage
(lub czymś w rodzaju4K
bajtów. Dokładny rozmiar strony jest zwracany wdwPageSize
parametrze). Ale poza tym cały blok pamięci zakres0x10000
bajtów (lub64K
w większości przypadków) zpAddress
nie będzie dostępny dla dalszych alokacji. W pewnym sensie, przydzielając 8 bajtów, równie dobrze możesz poprosić o 65536.Zatem morał z tej historii nie polega na zastępowaniu
VirtualAlloc
ogólnych alokacji pamięci w aplikacji. Musi być używany w bardzo szczególnych przypadkach, tak jak jest to zrobione w przypadku stosu poniżej. (Zwykle do rezerwowania / przydzielania dużych bloków pamięci).VirtualAlloc
Nieprawidłowe użycie może prowadzić do poważnej fragmentacji pamięci.HeapCreate / HeapAlloc / HeapFree / HeapDestroy
W skrócie, funkcje sterty są w zasadzie opakowaniem dla
VirtualAlloc
funkcji. Inne odpowiedzi tutaj stanowią całkiem niezłą koncepcję tego. Dodam, że w bardzo uproszczonym ujęciu sposób działania sterty jest następujący:HeapCreate
rezerwuje duży blok pamięci wirtualnej przez wywołanieVirtualAlloc
wewnętrzne (aZwAllocateVirtualMemory
konkretnie). Tworzy również wewnętrzną strukturę danych, która może śledzić dalsze alokacje mniejszych rozmiarów w zarezerwowanym bloku pamięci wirtualnej.Wszelkie wywołania
HeapAlloc
iHeapFree
faktycznie nie przydzielają / zwalniają żadnej nowej pamięci (chyba że, oczywiście, żądanie przekracza to, co zostało już zarezerwowaneHeapCreate
), ale zamiast tego odliczają (lubcommit
) wcześniej zarezerwowany duży fragment, dzieląc go na mniejsze bloki pamięci, które żąda użytkownik.HeapDestroy
z kolei wywołania,VirtualFree
które faktycznie zwalniają pamięć wirtualną.Wszystko to sprawia, że funkcje sterty są idealnymi kandydatami do ogólnego przydziału pamięci w aplikacji. Świetnie nadaje się do alokacji pamięci o dowolnym rozmiarze. Jednak niewielką ceną za wygodę funkcji sterty jest to, że wprowadzają one niewielki narzut
VirtualAlloc
przy rezerwowaniu większych bloków pamięci.Kolejną dobrą rzeczą w sterty jest to, że tak naprawdę nie musisz jej tworzyć. Zwykle jest tworzony dla Ciebie, gdy rozpoczyna się Twój proces. Można więc uzyskać do niego dostęp, wywołując funkcję GetProcessHeap .
malloc / free
Jest opakowaniem specyficznym dla języka dla funkcji sterty . W przeciwieństwie
HeapAlloc
,HeapFree
itd te funkcje nie będą działać tylko wtedy, gdy kod jest kompilowany dla systemu Windows, ale również dla innych systemów operacyjnych (takich jak Linux, itd)Jest to zalecany sposób przydzielania / zwalniania pamięci, jeśli programujesz w języku C. (Chyba że kodujesz określony sterownik urządzenia trybu jądra).
nowy / usuń
Przyjdź jako operatorzy zarządzania pamięcią wysokiego poziomu (no cóż, dla
C++
). Są specyficzne dlaC++
języka i podobnie jakmalloc
dlaC
, są również opakowaniami dlaheap
funkcji. Mają też całą masę własnego kodu, który zajmuje sięC++
specyficzną inicjalizacją konstruktorów, zwalnianiem alokacji w destruktorach, zgłaszaniem wyjątków itp.Te funkcje są zalecanym sposobem przydzielania / zwalniania pamięci i obiektów, jeśli programujesz w
C++
.Na koniec chciałbym poruszyć jeden komentarz dotyczący tego, co zostało powiedziane w innych odpowiedziach na temat
VirtualAlloc
współdzielenia pamięci między procesami.VirtualAlloc
samo w sobie nie pozwala na współdzielenie zarezerwowanej / alokowanej pamięci z innymi procesami. W tym celu należy użyćCreateFileMapping
interfejsu API, który może utworzyć nazwany blok pamięci wirtualnej, który można udostępniać innym procesom. Może również mapować plik na dysku do pamięci wirtualnej w celu uzyskania dostępu do odczytu / zapisu. Ale to inny temat.źródło
VirtualAlloc
jest wyspecjalizowaną alokacją systemu pamięci wirtualnej (VM) systemu operacyjnego. Alokacje w systemie maszyny wirtualnej muszą być dokonywane na poziomie szczegółowości alokacji, która (szczegółowość alokacji) zależy od architektury. Alokacja w systemie VM jest jedną z najbardziej podstawowych form alokacji pamięci. Alokacje maszyn wirtualnych mogą przybierać różne formy, pamięć niekoniecznie musi być dedykowana lub fizycznie zabezpieczona w pamięci RAM (choć może tak być). Alokacja maszyn wirtualnych jest zwykle alokacją specjalnego przeznaczenia , ponieważ alokacja musiHeapAlloc
jest w zasadzie to, comalloc
inew
jak w końcu zadzwonić. Został zaprojektowany tak, aby był bardzo szybki i użyteczny w wielu różnych typach scenariuszy alokacji ogólnego przeznaczenia. Jest to „Sterta” w klasycznym tego słowa znaczeniu. Sterty są w rzeczywistości konfigurowane przez aVirtualAlloc
, który jest używany do początkowej rezerwacji miejsca alokacji z systemu operacyjnego. Po zainicjowaniu przestrzeni przezVirtualAlloc
, różne tabele, listy i inne struktury danych są konfigurowane w celu utrzymania i sterowania działaniem HEAP. Część tej operacji polega na dynamicznym skalowaniu (powiększaniu i zmniejszaniu) pryzmy, dostosowywaniu pryzmy do określonych zastosowań (częste alokacje pewnego rozmiaru) itp.new
imalloc
są nieco takie same,malloc
jest zasadniczo dokładnym wezwaniem doHeapAlloc( heap-id-default )
;new
jednakże może [dodatkowo] skonfigurować przydzieloną pamięć dla obiektów C ++ . Dla danego obiektu C ++ będzie przechowywać vtables na stercie dla każdego wywołującego. Te tabele vtables są przekierowaniami do wykonania i stanowią część tego, co nadaje C ++ jego cechy OO, takie jak dziedziczenie, przeciążanie funkcji itp.Niektóre inne popularne metody alokacji, takie jak
_alloca()
i_malloca()
są oparte na stosie ; FileMappings są tak naprawdę przydzielaneVirtualAlloc
i ustawiane za pomocą określonych flag bitowych, które określają te mapowania jako typuFILE
.W większości przypadków pamięć należy przydzielać w sposób zgodny z wykorzystaniem tej pamięci;).
new
w C ++,malloc
dla C,VirtualAlloc
dla przypadków masowych lub IPC.*** Uwaga, duże alokacje pamięci wykonywane przez
HeapAlloc
są w rzeczywistości wysyłaneVirtualAlloc
po pewnym rozmiarze (kilkaset k lub 16 MB lub coś, o czym zapomniałem, ale dość duże :)).*** EDYCJA Krótko wspomniałem o IPC i
VirtualAlloc
jest też coś bardzo fajnego w powiązaniu, oVirtualAlloc
którym żaden z respondentów nie omówił.VirtualAlloc
Ex jest tym, czego jeden proces może użyć do przydzielenia pamięci w przestrzeni adresowej innego procesu. Najczęściej jest to używanew połączeniu,aby uzyskać zdalne wykonanie w kontekście innego procesu za pośrednictwem CreateRemoteThread (podobnie jakCreateThread
wątek jest po prostu uruchamiany w innym procesie).źródło
W konturze:
VirtualAlloc, HeapAlloc itp. To interfejsy API systemu Windows, które przydzielają pamięć różnych typów bezpośrednio z systemu operacyjnego. VirtualAlloc zarządza stronami w systemie pamięci wirtualnej Windows, podczas gdy HeapAlloc przydziela z określonej sterty systemu operacyjnego. Szczerze mówiąc, prawdopodobnie nigdy nie będziesz musiał używać żadnego z nich.
malloc to standardowa funkcja biblioteki C (i C ++), która przydziela pamięć do twojego procesu. Implementacje malloc zazwyczaj używają jednego z interfejsów API systemu operacyjnego do tworzenia puli pamięci podczas uruchamiania aplikacji, a następnie alokowania z niej podczas wykonywania żądań malloc
new to standardowy operator C ++, który przydziela pamięć, a następnie odpowiednio wywołuje konstruktory w tej pamięci. Może być zaimplementowany w zakresie malloc lub w zakresie interfejsów API systemu operacyjnego, w którym to przypadku również zwykle tworzy pulę pamięci podczas uruchamiania aplikacji.
źródło
VirtualAlloc
===>sbrk()
pod UNIXemHeapAlloc
====>malloc()
w systemie UNIXźródło
VirtualAlloc
=> Alokuje bezpośrednio do pamięci wirtualnej, rezerwujesz / zatwierdzasz w blokach. Jest to świetne rozwiązanie w przypadku dużych alokacji, na przykład dużych tablic.HeapAlloc
/new
=> alokuje pamięć na domyślnym stosie (lub innym stosie, który możesz utworzyć). To przydziela na obiekt i jest świetne dla mniejszych obiektów. Domyślna sterta jest możliwa do serializacji, dlatego ma gwarantowaną alokację wątków (może to powodować pewne problemy w scenariuszach o wysokiej wydajności i dlatego można tworzyć własne sterty).malloc
=> używa sterty środowiska wykonawczego C, podobnie jak wHeapAlloc
przypadku scenariuszy zgodności, ale jest to powszechne.W skrócie, sterta to po prostu fragment pamięci wirtualnej zarządzanej przez menedżera sterty (zamiast surowej pamięci wirtualnej)
Ostatnim modelem w świecie pamięci są pliki mapowane w pamięci, ten scenariusz jest świetny dla dużych porcji danych (takich jak duże pliki). Jest to używane wewnętrznie podczas otwierania pliku EXE (nie ładuje pliku EXE do pamięci, tylko tworzy plik mapowany w pamięci).
źródło