W jakich okolicznościach malloc może zwrócić wartość NULL?

Nigdy mi się to nie przytrafiło, a programuję od lat.

Może mi ktoś podać przykład nietrywialnego programu, w którym malloc faktycznie nie zadziała?

nie mówię o wyczerpaniu pamięci: Szukam prostego przypadku, gdy przydzielasz tylko jeden blok pamięci w ograniczonym rozmiarze podanym przez użytkownika, powiedzmy liczbę całkowitą, powoduje malloc niepowodzenie.

Author: RanZilber, 2012-02-01

9 answers

Tak.

Po prostu spróbuj malloc więcej pamięci niż Twój system może dostarczyć(albo wyczerpując przestrzeń adresową, albo pamięć wirtualną-w zależności od tego, która z tych wartości jest mniejsza).

malloc(SIZE_MAX)

Prawdopodobnie to zrobi. Jeśli nie, powtórz kilka razy, aż zabraknie.

 14
Author: Useless,
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-02-01 19:22:30

Musisz trochę popracować w systemach wbudowanych, często dostaniesz tam zwracane NULL: -)

[2]} znacznie trudniej jest wyczerpać pamięć w nowoczesnych systemach o ogromnej przestrzeni adresowej i przechowywaniu kopii zapasowych, ale nadal jest to całkiem możliwe w aplikacjach, w których przetwarzane są duże ilości danych, takich jak GIS lub bazy danych w pamięci, lub w miejscach, w których błędny kod powoduje wyciek pamięci.

Ale naprawdę nie ma znaczenia, czy nigdy wcześniej tego nie doświadczyłeś - standard mówi, że może tak się składa, że powinieneś to zaspokoić. Nie potrącił mnie samochód w ciągu ostatnich kilku dekad, ale to nie znaczy, że włóczę się po drogach, nie patrząc najpierw.

And re your edit:

Nie mówię o wyczerpaniu pamięci ...

Sama definicja wyczerpania pamięci to malloc nie dawanie pożądanej przestrzeni. Nie ma znaczenia, czy jest to spowodowane alokacją całej dostępnej pamięci, czy fragmentacją sterty, co oznacza, że nie można uzyskać blok przylegający, mimo że suma wszystkich wolnych bloków na arenie pamięci jest wyższa, lub sztucznie ogranicza wykorzystanie przestrzeni adresowej, np. za pomocą funkcji zgodnej ze standardami:

void *malloc (size_t sz) { return NULL; }

Standard C nie rozróżnia pomiędzy trybami niepowodzenia, tylko to, że się powiedzie lub zawiedzie.

 21
Author: paxdiablo,
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
2014-09-11 06:59:45

Każdy program napisany w języku c, który musi dynamicznie przydzielać więcej pamięci niż obecnie pozwala SYSTEM OPERACYJNY.

Dla zabawy, jeśli używasz ubuntu wpisz

 ulimit -v 5000

Każdy uruchomiony program najprawdopodobniej ulegnie awarii (z powodu awarii malloc), ponieważ ograniczyłeś ilość dostępnej pamięci do dowolnego procesu do niewielkiej ilości.

 8
Author: RussS,
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
2013-09-02 15:27:05

Jeśli twoja pamięć nie jest już całkowicie zarezerwowana (lub mocno fragmentowana), jedynym sposobem na zwrócenie malloc() wskaźnika NULL jest żądanie przestrzeni o rozmiarze zero:

char *foo = malloc(0);

Powołując się na standard C99, §7.20.3, podsekcja 1:

Jeśli rozmiar żądanej przestrzeni jest zerowy, zachowanie jest implementationdefiniowane: albo zwracany jest wskaźnik null, albo zachowanie jest tak, jakby Rozmiar był jakiś wartość niezerową, z tym że zwracany wskaźnik nie może być użyty do dostęp do obiektu.

Innymi słowy, malloc(0) może zwrócić NULL-wskaźnik lub poprawny wskaźnik do zera przydzielonych bajtów.

 5
Author: Philip,
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-02-02 08:29:15

Wystarczy sprawdzić stronę podręcznika malloc.

Po pomyślnym zakończeniu, wskaźnik do bloku pamięci przydzielonego przez funkcję.
Typ tego wskaźnika jest zawsze void*, który może być oddany do żądanego typu wskaźnika danych, aby mógł być dereferenceable.
Jeśli funkcja nie przydzieliła żądanego bloku pamięci, zwracany jest wskaźnik null.

 4
Author: starrify,
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-02-01 19:05:55

Ponieważ poprosiłeś o przykład, oto program, który (w końcu) zobaczy malloc return NULL:

perror();void*malloc();main(){for(;;)if(!malloc(999)){perror(0);return 0;}}
Co? Nie lubisz celowo zaciemnionego kodu? ;) (Jeśli działa przez kilka minut i nie rozbija się na twoim komputerze, zabij go, zmień 999 na większy numer i spróbuj ponownie.)

EDIT: jeśli to nie działa bez względu na to, jak duża jest liczba, to dzieje się tak, że Twój system mówi: "tu jest trochę pamięci!"ale dopóki nie spróbujesz go użyć, nie dostanie / align = "left" / W takim przypadku:

perror();char*p;void*malloc();main(){for(;;){p=malloc(999);if(p)*p=0;else{perror(0);return 0;}}
Powinno wystarczyć. Jeśli możemy użyć rozszerzeń GCC, myślę, że możemy go jeszcze zmniejszyć, zmieniając char*p;void*malloc(); na void*p,*malloc();, ale jeśli naprawdę chcesz grać w golfa, będziesz na kodzie Golf SE.
 3
Author: Chris Lutz,
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-02-01 19:23:26

Wybierz dowolną platformę, chociaż osadzenie jest prawdopodobnie łatwiejsze. malloc (LUB new) ton pamięci RAM (lub wyciek pamięci RAM w czasie, a nawet fragment za pomocą naiwnych algorytmów). Bum. malloc zwraca NULL dla mnie przy okazji, gdy dzieją się "złe" rzeczy.

W odpowiedzi na Twój edit. Jeszcze raz. Fragmentacja pamięci w czasie może sprawić, że nawet pojedyncza alokacja int może się nie udać. Należy również pamiętać, że malloc nie tylko przydziela 4 bajty na int, ale może zająć tyle miejsca jak chce. Posiada własną księgowość i dość często pobiera minimum 32-64 bajtów.

 3
Author: Michael Dorgan,
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-02-01 19:24:01

W mniej lub bardziej standardowym systemie, używając standardowego jednoparametrowego malloc, są trzy możliwe tryby awarii (o których myślę):

1) wielkość wnioskowanego przydziału jest niedozwolona. Na przykład niektóre systemy mogą nie zezwalać na przydział > 16M, nawet jeśli dostępna jest większa ilość miejsca.

2) przylegający wolny obszar o żądanym rozmiarze, z domyślną granicą, nie może być umieszczony w stercie. Nadal może być dużo sterty, ale po prostu nie wystarczy w jednym kawałku.

3) całkowita ilość przydzielonej sterty przekroczyła pewien "sztuczny" limit. Na przykład, użytkownik może mieć zakaz przydzielania więcej niż 100m, nawet jeśli jest 200m wolne i dostępne dla "systemu" w jednej połączonej sterty.

(oczywiście można uzyskać kombinacje 2 i 3, ponieważ niektóre systemy przydzielają sąsiadujące ze sobą bloki przestrzeni adresowej do sterty w miarę jej wzrostu, umieszczając" limit rozmiaru sterty " na sumie bloków.)

Zauważ, że niektóre środowiska obsługują dodatkowe parametry malloc, takie jako wyrównanie i identyfikator Puli, które mogą dodawać własne zwroty akcji.

 3
Author: Hot Licks,
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-02-01 20:23:26

Tak. Malloc zwróci NULL, gdy biblioteka jądra / systemu będzie pewna, że nie można przydzielić żadnej pamięci.

Powodem, dla którego zwykle nie widzisz tego na nowoczesnych maszynach, jest to, że Malloc tak naprawdę nie alokuje pamięci, ale raczej prosi o zarezerwowanie "wirtualnej przestrzeni adresowej" dla Twojego programu, abyś mógł w niej pisać. Jądra takie jak nowoczesny Linux faktycznie nad commit, to znaczy pozwalają przeznaczyć więcej pamięci niż Twój system może faktycznie dostarczyć (swap + RAM) tak długo, jak to wszystko pasuje w przestrzeni adresowej systemu (typowo 48-bitowe na platformach 64-bitowych, IIRC). Tak więc w tych systemach prawdopodobnie wywołasz zabójcę OOM, zanim wywołasz zwrot wskaźnika NULL. Dobrym przykładem jest 512MB RAM w 32-bitowej maszynie: trywialne jest napisanie programu w C, który zostanie zjedzony przez zabójcę OOM z powodu próby malloc wszystkich dostępnych RAM + swap.

(Overcomitting może być wyłączony podczas kompilacji w Linuksie, więc zależy to od opcji budowania, czy dany Jądro Linuksa będzie działać zbyt szybko. Jednak robią to jądra dystrybucji stockowej.)

 1
Author: user268396,
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-02-01 19:09:43