2017-07-28 34 views
6

Używam dwóch zmiennych, w których pamięć jest przydzielana dynamicznie, a ja drukuję lokalizacje w pamięci, ale nie są one kolejne. Czemu?Dlaczego lokalizacje w pamięci dla dwóch zmiennych, które są przydzielane dynamicznie, nie są następujące po sobie?

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    int *a = malloc(sizeof(int)); 
    int *b = malloc(sizeof(int)); 
    printf("\n a=%p \t b=%p \n",a,b); 
} 

Odpowiedzi I Get (w systemie Linux) są

1. Czas:

a=0x20a0010  b=0x20a0030 

2nd time:

a=0x657010  b=0x657030 

3 raz:

a=0x139e010  b=0x139e030 

Dlaczego dokładna różnica między lokalizacjami pamięci zmiennych a i b jest taka sama jak w 1., 2. i 3. czasie?

Czy jest to związane z pamięcią stronicowania?

Mój procesor ma 64 bity.

+2

to ma znaczenie? Jeśli potrzebujesz kolejnych adresów, powinieneś używać tablicy. –

+0

Chociaż jest to błędne, jest to interesujące pytanie. Nic więcej, możesz oczekiwać, że lokalizacje pamięci będą kolejno następujące po sobie. – Justin

+0

Twoje adresy mają rozmiar '32' bajtów.Gdyby były kolejne, można by się spodziewać, że będą "4" bajtowe od siebie (zakładając, że 'sizeof (int) == 4', które zazwyczaj jest) – Justin

Odpowiedz

2

System operacyjny obsługuje przydzielanie pamięci i nie ma gwarancji, że ta pamięć będzie ciągła przy dynamicznym przydzielaniu dwóch kolejnych zmiennych. Powinienem też wspomnieć, że jest to wynik mechanizmu obronnego znanego jako ASLR. ASLR chroni przed przepełnieniami bufora, losowo lokalizując proces podczas jego wykonywania, może to być stack, heap, and libraries. Dlatego zauważysz, że zmieniają się te adresy. Standardowo masz zagwarantowane tylko następujące.

ISO C11 7.22.3.4 Malloc

1) Streszczenie

#include <stdlib.h> 
void* malloc(size_t size); 

2) Opis funkcja malloc alokację pamięci dla obiektu, którego wielkość jest określona według wielkości i którego wartość jest nieokreślona.

3) Powrót Funkcja malloc zwraca wskaźnik zerowy lub wskaźnik do przydzielonego miejsca.

+0

Dziękujemy @Miket –

+0

* "System operacyjny obsługuje przydzielanie pamięci" * - Niekoniecznie. Po uzyskaniu pamięci środowisko wykonawcze może zapewnić alokacje, jeśli pamięć była wcześniej wolna. Zobacz także [Czy implementacje malloc zwrócą wolną pamięć z powrotem do systemu?] (Https://stackoverflow.com/q/2215259/608639) – jww

-2

Jeśli chcesz przydzielić pamięć alokującą wewnątrz i unique_ptr o rozmiarze dwóch tablic, i wskaż wskaźniki na końcu, a środek wskaźnika otrzymasz od unikalnego wskaźnika. Pamiętaj tylko, aby nie usuwać wskaźników aib.

std::unique_ptr<int> a(new int[na+nb]) 
int * aptr = a.get(); 
Int * bptr = a.get() + na; 
8

Różnica między dwiema kolejnymi alokacjami nie jest powiązana z przywołaniem. Twoje przydziały są tak małe, że znajdują się w segmencie danych. Libc obsługuje je wewnętrznie - przestrzeń poza swoimi bajtami sizeof int zawiera na ogół wskaźniki do poprzedniego i następnego bloku danych oraz wielkość alokacji - w końcu po prostu free dostanie wskaźnik i będzie musiała dowiedzieć się, ile pamięci ma do zwolnić.

Dodatkowo oba te wskaźniki są wyrównane do granicy 16-bajtowej. C11 7.22.3 mówi, że

Wskaźnik zwrócony jeśli przydział udaje się odpowiednio dostosowane tak, że może on być przyporządkowany do wskaźnik dla każdego rodzaju obiektu z podstawowym wymogiem wyrównania i umożliwia dostęp do takiego obiektu lub tablicę takich obiektów w przydzielonej przestrzeni (do momentu, gdy przestrzeń zostanie jawnie zwolniona).

Zatem nawet jeśli używasz ich do int średnia C wymaga, aby wskaźnik wrócił być dostosowane do każdego rodzaju danych - co na wdrożenie jest 16 bajtów.

Jeśli jednak przydzielisz obiekt, który jest bardzo duży, glibc zamapuje całe strony, używając zamiast tego mmap. Wtedy zdecydował (na moim 64-bitowa) wynosi dokładnie 16 bajtów od początku strony 4K:

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    int *a = malloc(12345678); 
    int *b = malloc(12345678); 
    printf("\n a=%p \t b=%p \n",a,b); 
} 

po uruchomieniu

% ./a.out 

a=0x7fb65e7b7010  b=0x7fb65dbf0010 

można zobaczyć mmap połączeń z strace ./a.out - tam wśród inny system nazywa istnieją

mmap(NULL, 12349440, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb65e7b7000 
mmap(NULL, 12349440, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb65dbf0000 

Jak, dlaczego ciągle się zmienia adresy od jednej egzekucji do drugiej - jest to spowodowane address space layout randomization, or ASLR - mechanizmem bezpieczeństwa, który utrudnia złośliwym crackerom przewidywalne wykorzystanie niezdefiniowanego zachowania w kodzie.


P.S. Jeśli naprawdę potrzebujesz dynamicznie przydzielić miejsce dla 2 int s na kolejne adresy, przydziel tablicę.

+0

Dlaczego wartości wskaźników są różne za każdym razem? – EJP

+0

@EJP dodał, że też –

+0

dziękuję @ antti haapala .. Ale nie chcę, aby ta pamięć była ciągła .. dlaczego nie jest ciągłe jest moje pytanie .. jak również wspomniałem o mojej lokalizacji pamięci po raz pierwszy, Drugi raz i trzeci czas mojego wykonania programu .. jeśli zauważysz, że lokalizacje i różnica b/w miejsca pamięci przydzielone .. jeśli znalazłeś coś niejednoznacznego ... –

0

W nocie na GNU Examples of malloc

nocie, że pamięć znajduje się po zakończeniu bloku prawdopodobnie być używany do czegoś innego; być może blok już przydzielony przez kolejne połączenie z malloc.

To faktycznie oznacza, że ​​dla każdego wywołania malloc systemu operacyjnego, w zależności od jego algorytm zarządzania pamięcią, znajdzie najodpowiedniejszego/prawidłowe/odpowiednie/wydajnego wolnego miejsca dla rozmówcy.

Na przykład:

void* p_1 = malloc(4); 
void* p_2 = malloc(4); 

[oooo][xxxx][oooo][oooo] 
^   ^
p_1   p_2