malloc(3)

NAZWA
malloc, free, calloc, realloc, reallocarray - przydziela i zwalnia pamięć dynamiczną

BIBLIOTEKA
Standardowa biblioteka C (libc, -lc)

SKŁADNIA
#include <stdlib.h>

void *malloc(size_t size);
void free(void *_Nullable p);
void *calloc(size_t n, size_t size);
void *realloc(void *_Nullable p, size_t size);
void *reallocarray(void *_Nullable p, size_t n, size_t size);

    Wymagane ustawienia makr biblioteki glibc (patrz feature_test_macros(7)):

reallocarray():
    Od glibc 2.29:
        _DEFAULT_SOURCE
    glibc 2.28 i wcześniejsze:
        _GNU_SOURCE

OPIS

  malloc()
Funkcja malloc() przydziela pamięć o rozmiarze size bajtów i zwraca wskaźnik do przydzielonej pamięci. Pamięć nie jest inicjowana. Jeśli size wynosi 0, to malloc() zwraca unikatową wartość wskaźnika, który potem można z powodzeniem przekazać do free() (zob. „Nieprzenośne zachowanie”).

  free()
Funkcja free() zwalnia obszar pamięci wskazywany przez p, który został wcześniej przydzielony za pomocą wywołania malloc() lub funkcji powiązanych. W przeciwnym przypadku lub gdy p zostało już uwolnione, funkcja zachowa się w sposób nieokreślony. Jeśli p jest równe NULL, nie zostanie wykonana żadna operacja.

  calloc()
Funkcja calloc() przydziela pamięć dla tablicy o liczbie n elementów o rozmiarze size bajtów każdy i zwraca wskaźnik do przydzielonej pamięci. Pamięć jest ustawiana na zero. Jeśli n lub size wynosi 0, to calloc() zwraca unikatową wartość wskaźnika, którą potem można z powodzeniem przekazać do free().

Jeśli przemnożenie n i size spowodowałoby przepełnienie liczby całkowitej, calloc() zwróci błąd. Przepełnienie nie zostałoby natomiast wykryte w następującym wywołaniu do malloc(), które spowodowałoby przydzielenie bloku pamięci o nieprawidłowym rozmiarze:

    malloc(n * size);

  realloc()
Funkcja realloc() zmienia rozmiar bloku pamięci wskazywanego przez p na size bajtów. Zawartość pamięci nie zostanie zmieniona w zakresie od początku obszaru do minimum ze starego i nowego rozmiaru. Jeśli nowy rozmiar jest większy od starego, to dodana pamięć nie zostanie zainicjowana.

Jeśli p jest równe NULL, to wywołanie jest równoważne malloc(size) dla wszystkich wartości size.

jeśli size jest równe zeru i p jest różny od NULL, to wywołanie jest równoważne z free(p) (lecz zob. „Nieprzenośne zachowanie” w sprawie problemów z przenośnością).

Jeżeli p jest różne od NULL, to musi on pochodzić z wcześniejszego wywołania malloc() lub powiązanych funkcji. Jeśli wskazywany obszar został przemieszczony, to wykonywane jest free(p).

  reallocarray()
Funkcja reallocarray() zmieni rozmiar (i ewentualnie przesunie) blok pamięci, na który wskazuje p, do wielkości odpowiednio dużej dla tablicy n elementów, każdy z których ma rozmiar size bajtów. Jest to równoważne wywołaniu

    realloc(p, n * size);

Jednak w odróżnieniu od tego wywołania realloc(), reallocarray() bezpiecznie zawiedzie w przypadku, w którym mnożenie prowadziłoby do przepełnienia. Jeśli takie przepełnienie wystąpi, reallocarray() zwróci błąd.

WARTOŚĆ ZWRACANA
Funkcje malloc(), calloc(), realloc() i reallocarray() zwracają wskaźnik do przydzielonej pamięci, który jest odpowiednio wyrównany dla dowolnego typu, który mieści się w żądanym lub mniejszym rozmiarze. W razie błędu funkcje te zwracają NULL i ustawiają errno. Próba przydzielenia więcej niż PTRDIFF_MAX bajtów jest uważana za błąd, ponieważ tak duże obiekty mogą później spowodować przepełnienie przy odjęciu wskaźnika.

Funkcja free() nie zwraca żadnej wartości i zachowuje errno.

Funkcje realloc() i reallocarray() zwracają NULL jeśli p nie wynosi NULL, a żądany rozmiar wynosi zero; nie jest to uważane za błąd (problemy z przenośnością opisano w rozdziale „Nieprzenośne zachowanie”). W innym przypadku, żądany wskaźnik może być taki sam jak p, jeśli alokacja nie została przesunięta (np. było miejsce na poszerzenie alokacji w miejscu) lub inny od p, jeśli alokację przeniesiono pod nowy adres. Jeśli funkcje te zawiodą, pierwotny blok pozostaje nienaruszony; nie jest zwalniany ani przesuwany.

BŁĘDY
calloc(), malloc(), realloc() i reallocarray() mogą zawieść z następującym błędem:

ENOMEM
    Brak wolnej pamięci. Prawdopodobnie aplikację dotknął limit RLIMIT_AS lub RLIMIT_DATA opisany w getrlimit(2). Innym powodem, może być przekroczenie liczby mapowań określonej w /proc/sys/vm/max_map_count przez proces wywołujący.

ATRYBUTY
Informacje o pojęciach używanych w tym rozdziale można znaleźć w podręczniku attributes(7).
Interfejs | Atrybut | Wartość
malloc(), free(), calloc(), realloc() | Bezpieczeństwo wątkowe | MT-bezpieczne

STANDARDY

malloc()
free()
calloc()
realloc()
    C23, POSIX.1-2024.

reallocarray()
    POSIX.1-2024.

  realloc(p, 0)
Zachowanie realloc(p, 0) nie jest zgodne z C99, C11, POSIX.1-2001, POSIX.1-2004, POSIX.1-2008, POSIX.1-2013, POSIX.1-2017 ani POSIX.1-2024. Normę C17 zmieniono tak, aby stało się zgodne, lecz podany w niej sposób czyni niemożliwym napisanie takiego kodu, który zawsze jest w stanie ustalić, czy wskaźnik wejściowy jest zwalniany po realloc(p, 0); z tego powodu w C23 stało się to ponownie zachowaniem niezdefiniowanym, przyjmując do wiadomości, że norma C17 była na tyle ogólna, że przewidziane zachowanie niezdefiniowane nie jest wcale gorszym rozwiązaniem.

reallocarray() ma te same problemy w glibc.

libc musl i systemy BSD są zgodne ze wszystkimi wersjami ISO C i POSIX.1.

gnulib zapewnia moduł realloc-posix, który dostarcza opakowania realloc() i reallocarray(), które są zgodne ze wszystkimi wersjami ISO C i POSIX.1.

Zaproponowano zestandaryzowanie zachowania BSD: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3621.txt.

HISTORIA

malloc()
free()
calloc()
realloc()
    POSIX.1-2001, C89.

reallocarray()
    glibc 2.26. OpenBSD 5.6, FreeBSD 11.0.

Od glibc 2.30, malloc() i powiązane funkcje odmówią rozmiarów większych od PTRDIFF_MAX.

free() zachowuje errno zaczynając od glibc 2.33.

  realloc(p, 0)
C89 było niejednoznaczne w określeniu realloc(p, 0). C99 częściowo to poprawiło.

Pierwotna implementacja w glibc byłaby zgodna z C99. Jednak, jak na ironię, próbując zachować zgodność z C99 jeszcze przed wydaniem standardu, glibc zmieniło swoje zachowanie w wersji glibc 2.1.1 na to, co ostatecznie stało się niezgodne z końcową wersją normy C99 (lecz jest to dyskusyjne, bowiem sformułowanie standardu wygląda na wewnętrznie sprzeczne).

UWAGI
Linux stosuje optymistyczną strategię przydzielania pamięci. Oznacza to, że gdy malloc() zwraca wartość różną od NULL, nie ma gwarancji, iż pamięć faktycznie jest dostępna. Jeśli okaże się, że systemowi brakło pamięci, niesławny zabójca OOM ("out-of-memory killer") zabije jeden lub więcej procesów. Więcej informacji zawiera opis plików /proc/sys/vm/overcommit_memory i /proc/sys/vm/oom_adj w proc(5) oraz plik Documentation/vm/overcommit-accounting.rst w źródłach jądra Linuksa.

Zwykle malloc() przydziela pamięć ze sterty i ustawia wymagany rozmiar sterty, używając sbrk(2). Podczas przydzielania bloków pamięci większych niż MMAP_THRESHOLD bajtów, implementacja malloc() w glibc używa prywatnych anonimowych map z mmap(2). MMAP_THRESHOLD domyślnie wynosi 128 kB, ale można to zmienić za pomocą mallopt(3). Przed Linuksem 4.7, limit zasobów RLIMIT_DATA (patrz getrlimit(2)) nie miał zastosowania do pamięci przydzielonej przy użyciu mmap(2); od Linuksa 4.7 limit ten stosuje się również dla alokacji dokonywanych za pomocą mmap(2).

Aby uniknąć uszkodzenia pamięci w aplikacjach wielowątkowych, funkcje te wewnętrznie stosują muteksy, chroniące struktury danych odnoszące się do zarządzania pamięcią. W aplikacji wielowątkowej, w której wątki jednocześnie przydzielają i zwalniają pamięć mogą występować oczekiwania na dostęp do muteksów. Aby przydział pamięci w aplikacji wielowątkowej był skalowalny, biblioteka glibc tworzy dodatkowe areny przydziału pamięci, jeśli wykryte zostanie oczekiwanie na mutex. Każda arena jest dużym regionem pamięci wewnętrznie zaalokowanym przez system (za pomocą brk(2) lub mmap(2)) i jest zarządzana przy użyciu jej własnych muteksów.

Jeśli dany program używa prywatnego alokatora pamięci, powinien to czynić przez zastąpienie malloc(), free(), calloc() i realloc(). Funkcje zastępujące muszą implementować opisywane zachowania glibc, w tym obsługę errno, alokację o zerowym rozmiarze i sprawdzanie przepełnienia; w innym przypadku inne funkcje biblioteczne mogą się załamać lub działać niepoprawnie. Na przykład, jeśli zastępcze free() nie będzie zachowywać errno, to pozornie niepowiązane funkcje biblioteczne mogą zawodzić bez prawidłowej przyczyny w errno. Prywatne alokatory pamięci mogą spowodować konieczność zastąpienia również innych funkcji glibc; więcej szczegółów w rozdziale „Replacing malloc” w podręczniku glibc.

Załamania w alokatorach pamięci są niemal zawsze związane z uszkodzeniami sterty, takimi jak przekroczenie rozmiaru przydzielonego fragmentu lub dwukrotne zwolnienie tego samego wskaźnika.

Implementację malloc() można dostosowywać za pomocą zmiennych środowiskowych. Szczegóły opisano w mallopt(3).

  Nieprzenośne zachowanie
Zachowanie tych funkcji, gdy żądany rozmiar wynosi zero, zależy od glibc; inne implementacje mogą zwrócić NULL bez ustawienia errno, a przenośne programy POSIX powinny tolerować takie zachowanie. Zob. realloc(3p).

POSIX wymaga ustawiania errno przez alokatory pamięci, przy niepowodzeniu. Jednak standard C tego nie wymaga, dlatego aplikacje przenośne na platformy poza POSIX nie powinny zakładać takiego zachowania.

Przenośne programy nie powinny używać prywatnych alokatorów pamięci, ponieważ POSIX i standard C nie dopuszczają zastępowania malloc(), free(), calloc() i realloc().

USTERKI
Programiści mogliby oczekiwać, że realloc(p, size) jest spójne z free(p) i malloc(size), jako że takie zachowanie występuje w ogólnym przypadku. Nie jest to wprost wymagane przez POSIX.1-2024 ani C11, jednak wszystkie zgodne implementacje są tu spójne.

Implementacja realloc() w glibc nie jest z tym spójna, dlatego wywoływanie realloc(p, 0) jest niebezpieczne w glibc.

Trywialnym obejściem problemu w glibc jest wywołanie w postaci realloc(p, size?size:1).

Obejściem problemu w reallocarray() w glibc, które cierpi na tę samą usterkę, byłoby reallocarray(p, n?n:1, size?size:1).

PRZYKŁADY
    #include <err.h>
    #include <stddef.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #define MALLOCARRAY(n, type)  ((type *) my_mallocarray(n, sizeof(type)))
    #define MALLOC(type)          MALLOCARRAY(1, type)

    static inline void *my_mallocarray(size_t n, size_t size);

    int
    main(void)
    {
        char  *p;

        p = MALLOCARRAY(32, char);
        if (p == NULL)
            err(EXIT_FAILURE, "malloc");

        strlcpy(p, "foo", 32);
        puts(p);
    }

    static inline void *
    my_mallocarray(size_t n, size_t size)
    {
        return reallocarray(NULL, n, size);
    }

ZOBACZ TAKŻE
valgrind(1), brk(2), mmap(2), alloca(3), malloc_get_state(3), malloc_info(3), malloc_trim(3), malloc_usable_size(3), mallopt(3), mcheck(3), mtrace(3), posix_memalign(3)

Szczegóły na temat implementacji biblioteki GNU C są dostępne pod adresem https://sourceware.org/glibc/wiki/MallocInternals.

TŁUMACZENIE
Tłumaczenie niniejszej strony podręcznika: Andrzej Krzysztofowicz <ankry@green.mf.pg.gda.pl>, Robert Luberda <robert@debian.org> i Michał Kułach <michal.kulach@gmail.com>

Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje o warunkach licencji można uzyskać zapoznając się z GNU General Public License w wersji 3 (https://www.gnu.org/licenses/gpl-3.0.html) lub nowszej. Nie przyjmuje się ŻADNEJ ODPOWIEDZIALNOŚCI.

Błędy w tłumaczeniu strony podręcznika prosimy zgłaszać na adres listy dyskusyjnej manpages-pl-list@lists.sourceforge.net.