Пользовательская реализация функции 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:

  1. ограничения выравнивания не существует. Я предположил, что не собираюсь ничего выравнивать.
  2. была демонстрационная программа, которая сделала серию mallocs и освобождает, чтобы проверить это, и у него не было никаких блоков памяти, которые были маленькими. Но это ничего не гарантирует.

изменить 2:

руководящие принципы из документации: Некоторые рекомендации по вашему коду:

  1. управление метаданными кучи в частной куче; не создавайте дополнительные связанные списки вне предоставленной частной кучи;
  2. конструкция mymalloc, myrealloc, myFree работать для всех возможных входов.
  3. myrealloc следует сделать следующее, Как realloc в библиотеке C++ : void* myrealloc( void* C, size_t newSize ):
    1. если newSize больше, чем размер куска в reallocThis:
      1. он должен сначала попытаться выделить кусок размере newSize на месте, так что базовый указатель нового куска также является reallocThis;
      2. если нет свободного места в выделение, следует выделить блок требуемого размера в другом регионе; и затем он должен скопировать содержимое из предыдущего куска.
      3. если функция не смогла выделить запрошенный блок памяти, a NULL возвращается указатель и блок памяти указал на аргументом reallocThis оставлено без изменений.
    2. если newSize меньше realloc должен уменьшить размер куска и всегда должен быть успешным.
    3. если newSize 0, то он должен работать как бесплатные.
    4. если reallocThis равно NULL, он должен работать как malloc.
    5. если reallocThis указатель, который уже был освобожден, тогда он должен завершиться с ошибкой, вернув NULL
  4. myFree должны не сбой при передаче указателя, который уже был освобожден.

2 ответов


вы, похоже,думаете о 256 байтах метаданных как о битовой карте для отслеживания свободного / использования по байтам.

Я бы рассмотрел следующее Как только одну возможную альтернативу:

Я бы начал с обработки 2048-байтовой кучи как 1024 "куска" по 2 байта каждый. Это дает вам 2 бита информации для каждого куска. Вы можете рассматривать первый из них как означающий, используется ли этот кусок, а второй-как означающий, является ли следующий кусок частью же логического блока текущей.

когда free вызывается функция, вы используете переданный адрес, чтобы найти правильную начальную точку в вашем растровом изображении. Затем вы проходите через биты, отмечая каждый фрагмент как свободный, пока не достигнете того, где второй бит установлен в 0, указывая конец текущего логического блока (т. е., что следующий 2-байтовый фрагмент не является частью текущего логического блока).

[Ой: только что заметил, что Росс Ридж уже предложил почти то же самое основная идея в комментарии.]


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

как для алгоритм как правило, простая и наивная реализация заключается в отслеживании нераспределенной памяти со связанным списком свободных блоков памяти, которые хранятся в порядке их расположения в памяти. Чтобы выделить место, вы ищете достаточно большой свободный блок. Затем измените список free, чтобы исключить это распределение. Чтобы освободить блок, вы добавляете его обратно в свободный список, объединяя соседние свободные блоки.

Это не хорошая реализация malloc по современным стандартам, но много старой памяти распределители работали таким образом.