Пользовательская реализация функции malloc
недавно мне задали вопрос, чтобы реализовать очень простой malloc со следующими ограничениями и начальных условий.
#define HEAP_SIZE 2048
int main()
{
privateHeap = malloc(HEAP_SIZE + 256); //extra 256 bytes for heap metadata
void* ptr = mymalloc( size_t(750) );
myfree( ptr );
return 0;
}
мне нужно реализовать mymalloc и myfree здесь используя точное место. 256 байт хорошо сопоставляется с 2048 битами, и я могу иметь битовый массив, хранящий, если байт выделен или если он свободен. Но когда я делаю myfree вызов с ptr, Я не могу сказать, сколько размера было выделено для начала. Я не могу использовать какие-либо дополнительные биты.
я, кажется, не думаю, что есть способ обойти это, но мне повторили, что это можно сделать. Есть предложения ?
EDIT 1:
- ограничения выравнивания не существует. Я предположил, что не собираюсь ничего выравнивать.
- была демонстрационная программа, которая сделала серию
mallocs и освобождает, чтобы проверить это, и у него не было никаких блоков памяти, которые были маленькими. Но это ничего не гарантирует.
изменить 2:
руководящие принципы из документации: Некоторые рекомендации по вашему коду:
- управление метаданными кучи в частной куче; не создавайте дополнительные связанные списки вне предоставленной частной кучи;
- конструкция
mymalloc,myrealloc,myFreeработать для всех возможных входов. -
myreallocследует сделать следующее, Какreallocв библиотеке C++ :void* myrealloc( void* C, size_t newSize ):- если
newSizeбольше, чем размер куска вreallocThis:- он должен сначала попытаться выделить кусок размере
newSizeна месте, так что базовый указатель нового куска также являетсяreallocThis; - если нет свободного места в выделение, следует выделить блок требуемого размера в другом регионе; и затем он должен скопировать содержимое из предыдущего куска.
- если функция не смогла выделить запрошенный блок памяти, a
NULLвозвращается указатель и блок памяти указал на аргументомreallocThisоставлено без изменений.
- он должен сначала попытаться выделить кусок размере
- если
newSizeменьшеreallocдолжен уменьшить размер куска и всегда должен быть успешным. - если
newSize0, то он должен работать как бесплатные. - если
reallocThisравно NULL, он должен работать какmalloc. - если
reallocThisуказатель, который уже был освобожден, тогда он должен завершиться с ошибкой, вернув NULL
- если
-
myFreeдолжны не сбой при передаче указателя, который уже был освобожден.
2 ответов
вы, похоже,думаете о 256 байтах метаданных как о битовой карте для отслеживания свободного / использования по байтам.
Я бы рассмотрел следующее Как только одну возможную альтернативу:
Я бы начал с обработки 2048-байтовой кучи как 1024 "куска" по 2 байта каждый. Это дает вам 2 бита информации для каждого куска. Вы можете рассматривать первый из них как означающий, используется ли этот кусок, а второй-как означающий, является ли следующий кусок частью же логического блока текущей.
когда free вызывается функция, вы используете переданный адрес, чтобы найти правильную начальную точку в вашем растровом изображении. Затем вы проходите через биты, отмечая каждый фрагмент как свободный, пока не достигнете того, где второй бит установлен в 0, указывая конец текущего логического блока (т. е., что следующий 2-байтовый фрагмент не является частью текущего логического блока).
[Ой: только что заметил, что Росс Ридж уже предложил почти то же самое основная идея в комментарии.]
распространенный способ реализации malloc отслеживать размер выделений памяти так free знает, насколько они велики, чтобы сохранить размер в байтах до возврата указателя malloc. Так сказать, вам нужно только два байта для хранения длины, когда вызывающий malloc запросы n байты памяти, вы фактически выделяете n + 2 байт. Затем вы сохраняете длину в первых двух байтах и возвращаете указатель на байт, только что прошедший мимо того места, где вы сохранили размер.
как для алгоритм как правило, простая и наивная реализация заключается в отслеживании нераспределенной памяти со связанным списком свободных блоков памяти, которые хранятся в порядке их расположения в памяти. Чтобы выделить место, вы ищете достаточно большой свободный блок. Затем измените список free, чтобы исключить это распределение. Чтобы освободить блок, вы добавляете его обратно в свободный список, объединяя соседние свободные блоки.
Это не хорошая реализация malloc по современным стандартам, но много старой памяти распределители работали таким образом.