Пользовательская реализация функции 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:
- ограничения выравнивания не существует. Я предположил, что не собираюсь ничего выравнивать.
- была демонстрационная программа, которая сделала серию
malloc
s и освобождает, чтобы проверить это, и у него не было никаких блоков памяти, которые были маленькими. Но это ничего не гарантирует.
изменить 2:
руководящие принципы из документации: Некоторые рекомендации по вашему коду:
- управление метаданными кучи в частной куче; не создавайте дополнительные связанные списки вне предоставленной частной кучи;
- конструкция
mymalloc
,myrealloc
,myFree
работать для всех возможных входов. -
myrealloc
следует сделать следующее, Какrealloc
в библиотеке C++ :void* myrealloc( void* C, size_t newSize )
:- если
newSize
больше, чем размер куска вreallocThis
:- он должен сначала попытаться выделить кусок размере
newSize
на месте, так что базовый указатель нового куска также являетсяreallocThis
; - если нет свободного места в выделение, следует выделить блок требуемого размера в другом регионе; и затем он должен скопировать содержимое из предыдущего куска.
- если функция не смогла выделить запрошенный блок памяти, a
NULL
возвращается указатель и блок памяти указал на аргументомreallocThis
оставлено без изменений.
- он должен сначала попытаться выделить кусок размере
- если
newSize
меньшеrealloc
должен уменьшить размер куска и всегда должен быть успешным. - если
newSize
0, то он должен работать как бесплатные. - если
reallocThis
равно NULL, он должен работать какmalloc
. - если
reallocThis
указатель, который уже был освобожден, тогда он должен завершиться с ошибкой, вернув NULL
- если
-
myFree
должны не сбой при передаче указателя, который уже был освобожден.
2 ответов
вы, похоже,думаете о 256 байтах метаданных как о битовой карте для отслеживания свободного / использования по байтам.
Я бы рассмотрел следующее Как только одну возможную альтернативу:
Я бы начал с обработки 2048-байтовой кучи как 1024 "куска" по 2 байта каждый. Это дает вам 2 бита информации для каждого куска. Вы можете рассматривать первый из них как означающий, используется ли этот кусок, а второй-как означающий, является ли следующий кусок частью же логического блока текущей.
когда free
вызывается функция, вы используете переданный адрес, чтобы найти правильную начальную точку в вашем растровом изображении. Затем вы проходите через биты, отмечая каждый фрагмент как свободный, пока не достигнете того, где второй бит установлен в 0, указывая конец текущего логического блока (т. е., что следующий 2-байтовый фрагмент не является частью текущего логического блока).
[Ой: только что заметил, что Росс Ридж уже предложил почти то же самое основная идея в комментарии.]
распространенный способ реализации malloc отслеживать размер выделений памяти так free
знает, насколько они велики, чтобы сохранить размер в байтах до возврата указателя malloc
. Так сказать, вам нужно только два байта для хранения длины, когда вызывающий malloc
запросы n
байты памяти, вы фактически выделяете n + 2
байт. Затем вы сохраняете длину в первых двух байтах и возвращаете указатель на байт, только что прошедший мимо того места, где вы сохранили размер.
как для алгоритм как правило, простая и наивная реализация заключается в отслеживании нераспределенной памяти со связанным списком свободных блоков памяти, которые хранятся в порядке их расположения в памяти. Чтобы выделить место, вы ищете достаточно большой свободный блок. Затем измените список free, чтобы исключить это распределение. Чтобы освободить блок, вы добавляете его обратно в свободный список, объединяя соседние свободные блоки.
Это не хорошая реализация malloc по современным стандартам, но много старой памяти распределители работали таким образом.