GNU C library имеет несколько функций для динамического выделения памяти .
Любой процесс имеет в памяти свой виртуальный адрес.
Виртуальная память обычно делится на 4-килобайтные страницы , которые называются фреймами.
Страницы могут располагаться как в реальной памяти , так и на диске.
Когда процесс обращается к странице , она должна находиться в реальной памяти ,
в противном случае , когда процесс спит , страница должна быть сброшена на диск до следующего обращения.
Этот процесс называется paging . Если процесс обращается к странице ,
а ее в реальной памяти нет , имеет место быть т.н.page fault.
Ядро уже должно быть озабочено разрешением этой проблемы .
Для того , чтобы по одному адресу не было записано 2 обьекта , существует понятие
т.н. memory allocation . Выделение памяти может быть вызвано как заранее,
на этапе программирования, так и в результате запуска самого процесса.
Можно еще выделить 3-й путь - fork() .
Процесс запускается системной функцией exec .Стартовое выделение памяти произошло.
Дальше может произойти программное выделение,которое можно разделить на 2 вида :
автоматическое и динамическое. Другой формой динамического выделения является Memory-mapped I/O.
Программа может и удалять выделенную память.
У каждого процесса в памяти есть 3 главных сегмента :
1. text segment
2. data segment
3. stack segment
Static allocation происходит при инициализации статических или глобальных переменных.
Automatic allocation происходит при создании локальных переменных.
Динамическое же выделение памяти в Си не имеет соответствующего динамического типа переменной.
Динамически память может быть выделена либо с помощью системного вызова , либо с помощью указателя .
Например вызов malloc(size_t size) может выделить память произвольного размера.
В следующем примере выделяется память под структуру , которая заполняется нулями :
struct foo *ptr;
...
ptr = (struct foo *) malloc (sizeof (struct foo));
if (ptr == 0) abort ();
memset (ptr, 0, sizeof (struct foo));
При выделении памяти под символьную строку размер памяти должен быть на единицу больше длины строки.
Освобождение памяти выполняется с помощью free.
Ниже дан пример корректного освобождения памяти .
struct chain
{
struct chain *next;
char *name;
}
void
free_chain (struct chain *chain)
{
while (chain != 0)
{
struct chain *next = chain->next;
free (chain->name);
free (chain);
chain = next;
}
}
Функция realloc (void *ptr, size_t newsize) увеличивает размер уже выделенного блока памяти.
Функция calloc (size_t count, size_t eltsize) выделяет память для count элементов , каждый из которых
размером eltsize .
Эти функции при выделении памяти возвращают адрес,который кратен 8 .
Если вам нужен возвращаемый адрес , который кратен 2 , используйте
memalign (size_t boundary, size_t size) ,где boundary - кратность, начиная с 2 .
Функция mallopt (int param, int value) позволяет при выделении использовать дополнительные параметры.
В системном хидере`malloc.h' имеется набор переменных , с помощью которых можно
дебажить вызовы функйий malloc , realloc , откуда бы они не вызывались .
Это переменые __malloc_hook,__realloc_hook,__free_hook .
Для того,чтобы дебажить выделение памяти , проще всего применить такую конструкцию :
#include < mcheck.h>
int
main (int argc, char *argv[])
{
#ifdef DEBUGGING
mtrace ();
#endif
...
}
Для того , чтобы включить/отключить дебаг памяти в любой момент времени , можно сделать так:
#include < mcheck.h>
#include < signal.h>
static void
enable (int sig)
{
mtrace ();
signal (SIGUSR1, enable);
}
static void
disable (int sig)
{
muntrace ();
signal (SIGUSR2, disable);
}
int
main (int argc, char *argv[])
{
...
signal (SIGUSR1, enable);
signal (SIGUSR2, disable);
...
}
Функция alloca (size_t size); выделяет память и после ее использования автоматически ее освобождает.
Эта функция очень быстра и не вызывает фрагментации памяти.
Функция brk (void *addr) увеличивает верхнюю границу сегмента данных.
|
|