Есть ли какая-то «свободная» память - PullRequest
3 голосов
/ 05 июля 2011
int main()
{
    char *s1, *sTemp;

    s1 = (char*)malloc(sizeof(char)*7);
    *(s1 + 0) = 'a';
    *(s1 + 1) = 'b';
    *(s1 + 2) = 'c';
    *(s1 + 3) = 'd';
    *(s1 + 4) = 'e';
    *(s1 + 5) = 'f';
    *(s1 + 6) = '\0';

    sTemp = (s1 + 3);

    free(sTemp); // shud delete d onwards. But it doesn't !!

    return 0;
}

Здравствуйте,

В коде C выше sTemp должен указывать на 3-ю ячейку за пределами s1 (занятую 'd'). Так что при вызове free(sTemp) Я ожидаю, что что-то будет удалено из этого места и далее.

(я намеренно упоминаю ' что-то ', поскольку мотивом моего эксперимента изначально было выяснение, в каком месте работает свободный ())

Однако я получаю SIGABRT в free().

Как free() узнает, что это не начало чанка.и, соответственно, мы можем освободить память только с самого начала?[это только свободные указатели, которые free() может принимать ??]

Ждем ответов:)

Ответы [ 6 ]

7 голосов
/ 05 июля 2011

Из справочных страниц

free() освобождает пространство памяти, на которое указывает ptr, которое должно было быть возвращено предыдущим вызовом malloc(), calloc() или realloc().В противном случае, или если free(ptr) уже был вызван ранее, происходит неопределенное поведение.

Источник: http://linux.die.net/man/3/free

3 голосов
/ 05 июля 2011

О фактическом вопросе "откуда free знает ...":

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

Не указано, как именно среда выполнения хранит книгуразмеры выделения, только то, что вы должны никогда передавать любой указатель на free, который не происходит от функции семейства malloc.

Обычно это работаетmalloc выделяя немного больше памяти, чем необходимо [1] и записывая некоторые метаданные в память , предшествующие возвращаемому адресу.free затем просто просматривает, например, ptr[-8] или что-либо еще (подробности реализации!), Чтобы прочитать эти метаданные.
Затем он может дополнительно выполнить некоторые проверки согласованности и может определить размер блока памяти (одна тривиальная проверка согласованности, котораявероятно, всегда выполняется проверка правильности выравнивания указателя).

Сказав это, пожалуйста, пожалуйста, пожалуйста, даже не думайте об игре с этими метаданными.

[1] Часто это так или иначе выполняется, чтобы удовлетворить требования выравнивания и из-за внутренних компонентов распределителя (большинство распределителей управляют памятью в разных «корзинах» фиксированного размера), так что если вы выделяете, скажем, 4 байта, вы номинально получаете 4 байта, но среда выполнения действительно выделяла 8 или 16 байтов большую часть времени (без вашего ведома).

2 голосов
/ 05 июля 2011

Я думаю, что вы не можете освободить память, потому что free не знает, сколько памяти освободить. Ваша программа имеет информацию о возвращенном адресе malloc (), и не для каждого адреса в этом пространстве. Так что вы можете освободить (s1), но not free (s1 + 3). Также вы можете обрабатывать ваши указатели как массив в этом примере: s1 [0] = 'а';

2 голосов
/ 05 июля 2011

Вы можете использовать только free() указатели, которые были malloc ed (или calloc ed, realloc ed). Если вы попытаетесь освободить только часть памяти, передав другой указатель (даже тот, который является «частью» другого указателя), среда выполнения C не будет удовлетворена (как вы можете видеть).

1 голос
/ 05 июля 2011

Вы можете только free() память, которая была ранее malloc ed, calloc ed или realloc ed, как сказали dlev и Daniel.

Причина этого зависит от реализации, но включает в себя метод отслеживания выделенной памяти.

Эффективное выделение памяти является сложной проблемой, потому что разные алгоритмы выделения памяти работают хорошо в зависимости от того, как выделяется память: несколько небольших кусков, половина из которых освобождается, затем захватываются несколько более крупные блоки и т. Д.

Цель состоит в том, чтобы сохранить минимальный размер блока памяти, используемого программой (обычно этот блок будет непрерывным блоком виртуальной памяти), сохраняя при этом использование пространства в этом блоке чрезвычайно высоким (несколько пробелов). между используемыми сегментами памяти).

Помните, что эти блоки не могут быть перемещены, за исключением случаев, когда они realloc ed, поэтому всегда будет некоторое место впустую.

Чтобы свести к минимуму потери, метаданные о (как минимум) размере блока сохраняются непосредственно перед ним. Распределитель памяти может просматривать используемые блоки при определении того, как обрабатывать новый запрос. Если вы выберете случайное место в памяти, будь то часть ранее выделенной области или нет, эти метаданные не будут присутствовать, и free не сможет определить, что следует освободить.

0 голосов
/ 06 июля 2011

Вы не можете освободить этот указатель так, как вы делаете, проверьте этот вопрос и ответ на него: Ошибка забивания памяти

...