Autor Wątek: Tajemnicze zachowanie new  (Przeczytany 1348 razy)

Offline Lerhes

  • Użytkownik

  • +1
# Wrzesień 28, 2016, 00:32:51
Cześć,

Trafiłem na "trochę dziwne" zachowanie operatora new i bardzo proszę o wyjaśnienie poniższych obserwacji. Sprawdziłem w standardzie języka C++, że pamięć zaalokowana operatorem new nie jest zerowana (no chyba że użyjemy nawiasów). Czyli:
int * tab1 = new[100]; //Nie mamy zerowania
int* tab2 = new[100](); //Mamy zerowanie
Nic w tym dziwnego. Zróbmy mały eksperyment:
http://ideone.com/fblet5
Wynik nie jest specjalnie zaskakujący - zaalokowałem 200 intów. Ustawiłem w tym obszarze same -1 i potem zwolniłem pamięć. Ponowna alokacja takiej samej tablicy dała mi ten sam adres (tutaj może być czasami inny adres, ale akurat to nieistotne) i mam te same wartości (-1) co też nie jest jakieś dziwne (bo niby kiedy miała się zmienić). Kompilator dołączony do Visual Studio daje troszkę inne wyniki, ale generalnie jest podobnie.

Ok, teraz meritum sprawy, podciągnijmy znacznie rozmiar alokowanej tablicy, z 200 elementów do 2000000.
http://ideone.com/W3mLvH
I teraz psikus którego nie rozumiem. Dlaczego przy alokacji dużego obszaru pamięci, ten obszar jest zerowany?
Jeszcze raz wyjaśnię o co mi chodzi. Najpierw alokuję duży obszar pamięci i ustawiam w nim -1. Potem usuwam ten obszar i alokuję ponownie równie duży. Dostaję ten sam adres. Ale dlaczego "gratis" zostały w nim ustawione zera?
Taki sam wynik jest z Visual Studio.

Wiem że nie mogę polegać na takim zachowaniu kompilatora, bo jest niezgodne ze standardem. Natomiast ciekawi mnie, dlaczego duży obszar zaalokowanej pamięci jest zerowany, a mały nie. Wydaje mi się, że przecież takie zerowanie dużego obszaru tylko spowolni program (a wydajność jest przecież najważniejsza w C++ :) ).

Update: W sumie to można pytanie "uprościć" do pytania o malloc - bo przecież new woła malloc (plus trochę magii). Stosowanie samego malloc daje te same wyniki.

Pozdrawiam,
Lerhes
« Ostatnia zmiana: Wrzesień 28, 2016, 00:39:37 wysłana przez Lerhes »

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline karol57

  • Użytkownik

  • +5
# Wrzesień 28, 2016, 01:01:45
Uwaga: Mogę pisać głupoty.
1. Alokujesz więcej niż stronę pamięci, więc biblioteka standardowa standardowa uznaje, że przy zwalnianiu nie pozwala sobie na trzymanie tych ~7 MiB pamięci i zwalnia ją do systemu.
2. Kolejna alokacja pobiera z systemu pamięć, która jest zerowana przez system dla bezpieczeństwa.

Jak alokowałeś mało to biblioteka standardowa pewnie nawet nie zwalniała tej pamięci uznając, że potem ją użyjesz.

A jednak nie napisałem głupot: http://stackoverflow.com/questions/8029584/why-does-malloc-initialize-the-values-to-0-in-gcc
« Ostatnia zmiana: Wrzesień 28, 2016, 01:03:16 wysłana przez karol57 »

Offline Reg

  • Administrator
    • Adam Sawicki - Home Page

  • +4
# Wrzesień 28, 2016, 12:52:53
W nowoczesnych systemach operacyjnych pamięć jest wirtualna. Przestrzeń adresowa, czyli wartości wskaźników też są wirtualne. Dopiero gdzieś na niższym poziomie one się mapują na strony pamięci RAM (albo pliku wymiany), które zawierają konkretne dane. Tak więc obstawiałbym taką możliwość, że dostając nawet przypadkiem drugi raz ten sam adres wcale nie musisz trafiać do tych samych stron pamięci. Może nawet dana strona w ogóle nie jest rezerwowana, dopóki po raz pierwszy jej nie użyjesz. Nie wiem dokładnie.

Natomiast w ogólności nie należy polegać na takim czy innym zaobserwowanym zachowaniu ani używać niezainicjalizowanej pamięci, tylko zawsze pamiętać, żeby samemu wypełnić ją czymś sensownym przed jej odczytywaniem.

Offline Lerhes

  • Użytkownik

# Wrzesień 28, 2016, 13:33:34
Cześć,

Dzięki za odpowiedzi. Szczególne podziękowanie dla Karola - wydaje mi się, że właśnie z tym mam do czynienia w przypadku mojego programu.
Tak właśnie mi się wydawało, że ma to coś wspólnego z pobieraniem pamięci od OS, ale dziwne mi się wydawało, żeby przy okazji OS zerował tę pamięć. Ale fakt - gdyby tego nie robił, to programy mogłyby analizować otrzymaną pamięć i próbować na tej podstawie jakiejś formy ataku.

Jeszcze raz dziękuję za pomoc.

Pozdrawiam,
Lerhes