В идеале realloc()
будет просто видеть, достаточно ли свободной памяти за пределами текущего блока, и, если это так, просто настроить структуры данных арены, чтобы расширить текущий блок на месте. Это избавляет от дорогостоящей операции копирования и снижает вероятность сбоя выделения. Это для увеличения размера. Для сокращения вы должны всегда иметь возможность делать это на месте, отправляя остаток текущего блока обратно в свободный пул.
Делая malloc / free, если у вас есть 100K на арене с выделенным одиночным блоком 60K, вызов вашего mm_realloc
для настройки размера до 50K не удастся.
Однако, это работоспособное решение, по крайней мере, для первой попытки, поэтому вот как я бы его реализовал:
void *mm_realloc (void *ptr, size_t size) {
int minsize;
void *newptr;
// Allocate new block, returning NULL if not possible.
newptr = malloc (size);
if (newptr == NULL) return NULL;
// Don't copy/free original block if it was NULL.
if (ptr != NULL) {
// Get size to copy - mm_getsize must give you the size of the current block.
// But, if new size is smaller, only copy that much. Many implementations
// actually reserve the 16 bytes in front of the memory to store this info, e.g.,
// +--------+--------------------------------+
// | Header | Your data |
// +--------+--------------------------------+
// ^
// +--- this is your pointer.
// <- This is the memory actually allocated ->
minsize = mm_getsize (ptr);
if (size < minsize)
minsize = size;
// Copy the memory, free the old block and return the new block.
memcpy (newptr, ptr, minsize);
free (ptr)
}
return newptr;
}
Одна вещь, которую вы заметите, чего вам не хватает, это то, что она должна скопировать только достаточное количество байтов для наименьшего из старых и новых блоков. В противном случае вы рискуете получить дамп памяти, переполнив один из них.
Кроме того, ваш цикл на самом деле не копировал данные, он устанавливал каждый байт блока в свое смещение, и он терял старый указатель при выделении нового, поэтому я использовал newptr
, чтобы держать их отдельно .