Как работают malloc () и free ()? - PullRequest
261 голосов
/ 13 июля 2009

Я хочу знать, как работают malloc и free.

int main() {
    unsigned char *p = (unsigned char*)malloc(4*sizeof(unsigned char));
    memset(p,0,4);
    strcpy((char*)p,"abcdabcd"); // **deliberately storing 8bytes**
    cout << p;
    free(p); // Obvious Crash, but I need how it works and why crash.
    cout << p;
    return 0;
}

Я был бы очень признателен, если бы ответ был глубоким на уровне памяти, если это возможно.

Ответы [ 13 ]

3 голосов
/ 13 июля 2009

Ваша программа дает сбой, потому что она использовала память, которая не принадлежит вам. Он может быть использован кем-то другим или нет - если вам повезет, что вы потерпите крах, если нет, то проблема может оставаться скрытой в течение длительного времени и возвращаться и кусать вас позже.

Что касается реализации malloc / free - этой теме посвящены целые книги. По сути, распределитель получит большие объемы памяти из ОС и будет управлять ими за вас. Вот некоторые из проблем, которые должен решить распределитель:

  • Как получить новую память
  • Как его сохранить - (список или другая структура, несколько списков для фрагментов памяти разного размера и т. Д.)
  • Что делать, если пользователь запрашивает больше памяти, чем доступно в данный момент (запросить больше памяти у ОС, объединить некоторые из существующих блоков, как их точно соединить, ...)
  • Что делать, когда пользователь освобождает память
  • Распределители отладки могут дать вам больший кусок, который вы запросили, и заполнить его некоторым байтовым шаблоном, когда вы освобождаете память, распределитель может проверить, записано ли вне блока (что, вероятно, происходит в вашем случае) ...
2 голосов
/ 13 июля 2009

Трудно сказать, потому что фактическое поведение отличается в разных компиляторах / средах выполнения. Даже сборки отладки / выпуска имеют различное поведение. Отладочные сборки VS2005 будут вставлять маркеры между выделениями для обнаружения повреждения памяти, поэтому вместо сбоя он будет утвержден в free ().

1 голос
/ 17 сентября 2013

Также важно понимать, что простое перемещение указателя разрыва программы с помощью brk и sbrk на самом деле не выделяет памяти, а просто устанавливает адресное пространство. Например, в Linux память будет «поддерживаться» фактическими физическими страницами при обращении к этому диапазону адресов, что приведет к сбою страницы и в конечном итоге приведет к тому, что ядро ​​вызовет распределитель страниц, чтобы получить резервную страницу.

...