Подтвердить что ты не робот

Могу ли я предположить, что вызов realloc с меньшим размером освободит остаток?

Давайте рассмотрим этот очень короткий фрагмент кода:

#include <stdlib.h>

int main()
{
    char* a = malloc(20000);
    char* b = realloc(a, 5);

    free(b);
    return 0;
}

После прочтения man-страницы realloc я не был полностью уверен, что вторая строка приведет к освобождению дополнительных байтов 19995. Чтобы процитировать справочную страницу: The realloc() function changes the size of the memory block pointed to by ptr to size bytes., но из этого определения я могу быть уверен, что остальное будет освобождено?

Я имею в виду, что блок, на который указывает b, безусловно, содержит 5 свободных байтов, так ли будет достаточно, чтобы ленивый оператор-ассистент просто ничего не делал для строки realloc?

Примечание. Я использую распределитель, который освобождает 19 995 дополнительных байтов, как показано valgrind при комментировании строки free(b):

==4457== HEAP SUMMARY:
==4457==     in use at exit: 5 bytes in 1 blocks
==4457==   total heap usage: 2 allocs, 1 frees, 20,005 bytes allocated
4b9b3361

Ответ 1

Да, гарантируется стандартом C, если новый объект может быть выделен.

(C99, 7.20.3.4p2) "Функция realloc освобождает старый объект, на который указывает ptr, и возвращает указатель на новый объект, размер которого задан размером."

Ответ 2

Да, если это удастся.

В вашем фрагменте кода показана хорошо известная, гнусная ошибка:

char* b = (char*) realloc(a, 5);

Если это удастся, память, ранее выделенная для a, будет освобождена, а b укажет на 5 байтов памяти, которые могут перекрывать или не перекрывать исходный блок.

Однако если сбой вызова, b будет null, но a будет по-прежнему указывать на его исходную память, которая будет по-прежнему действительна. В этом случае вам нужно free(a) освободить память.

Это еще хуже, если вы используете общую (опасную) идиому:

a = realloc(a, NEW_SIZE);     // Don't do this!

Если вызов realloc завершается с ошибкой, a будет null, и его исходная память будет потеряна, что сделает ее безвозвратно потерянной до выхода вашей программы.

Ответ 3

Это зависит от вашей реализации libc. Все следующее соответствует поведению:

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

Также возможно

  • возвращает нулевой указатель, если новый блок не может быть выделен

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

Разумная реализация libc будет использовать некоторую эвристику, чтобы определить, какое решение наиболее эффективно.

Также имейте в виду, что это описание находится на уровне реализации: Семантически, realloc() всегда освобождает объект, пока распределение не прерывается.

Ответ 4

Функция realloc имеет следующий контракт:

void * result = realloc (ptr, new_size)

  • Если результат равен NULL, то ptr все еще действителен и не изменяется.
  • Если результат не равен NULL, тогда ptr теперь недействителен (как если бы он был освобожден) и больше никогда не должен использоваться. результат теперь является указателем на точно байты данных new_size.

Точные сведения о том, что происходит под капотом, являются специфичными для реализации - например, результат может быть равен ptr (но дополнительное пространство за пределами new_size больше не нужно касаться), и realloc может звонить бесплатно или может выполнять свои собственные внутренние свободное представление. Главное, что в качестве разработчика вы больше не несете ответственность за ptr, если realloc возвращает non-null, и вы по-прежнему несете ответственность за него, если realloc возвращает NULL.

Ответ 5

Кажется маловероятным, что 19995 байт были освобождены. Скорее всего, что realloc заменил блок размером 20000 байтов на другой 5-байтовый блок, то есть блок размером 20000 байт был освобожден и был выделен новый 5-байтовый блок.