C - Создайте собственную функцию free()

Сегодня я появился на собеседование, и интервьюер спросил меня об этом,

  • Скажите шаги, как вы создадите собственную функцию free( ) для освободить выделенную память.
  • Как он может быть более эффективным, чем функция C по умолчанию free()? Что вы можете сделать?

Я был в замешательстве, не мог придумать способ дизайна.

Как вы думаете, ребята?


РЕДАКТИРОВАТЬ: Поскольку нам нужно знать, как работает malloc(), можете ли вы рассказать мне о способах написания нашей собственной функции malloc()

Ответы

Ответ 1

Это на самом деле довольно неопределенный вопрос, и, вероятно, почему вы запутались. Имеет ли он в виду, что, учитывая существующую реализацию malloc, как вы собираетесь пытаться разработать более эффективный способ освободить базовую память? Или он ожидал, что вы начнете обсуждать различные варианты реализации malloc и их преимущества и проблемы? Он ожидал, что вы узнаете, как виртуальная память функционирует на архитектуре x86?

Кроме того, более эффективно, имеет ли он значение более эффективного пространства или более эффективного времени? Нужно ли детекционировать дефиницию free()? Должно ли оно вернуть как можно больше памяти в ОС, поскольку это в среде с низкой памятью и многозадачностью? Какие наши критерии здесь?

Трудно сказать, с чего начать с такого расплывчатого вопроса, кроме как начать задавать свои вопросы, чтобы получить разъяснения. В конце концов, чтобы создать свою свободную функцию, вам сначала нужно знать, как реализуется malloc. Скорее всего, вопрос в том, действительно ли вы знали о том, как реализовать malloc.

Если вы не знакомы с внутренними функциями управления памятью, самый простой способ начать с понимания того, как реализован malloc, - это сначала написать свой собственный.

Ознакомьтесь с этой статьей IBM DeveloperWorks под названием "Управление внутренней памятью" для начала.

Но прежде чем вы сможете написать свой собственный malloc/free, вам сначала понадобится выделить/освободить память. К сожалению, в ОС защищенного режима вы не можете напрямую обращаться к памяти на аппарате. Итак, как вы его получите?

Вы запрашиваете ОС для этого. Благодаря функциям виртуальной памяти x86 любой фрагмент оперативной памяти или своп-памяти может быть сопоставлен с адресом памяти операционной системой. То, что ваша программа видит как память, может быть физически фрагментировано по всей системе, но благодаря диспетчеру виртуальной памяти ядра все выглядит одинаково.

Ядро обычно предоставляет системные вызовы, которые позволяют вам отображать дополнительную память для вашего процесса. В более старой ОС UNIX обычно было brk/sbrk, чтобы увеличить память кучи на краю вашего процесса или уменьшить его, но многие системы также предоставляют mmap/munmap, чтобы просто отобразить большой блок памяти кучи. Это только после того, как вы имеют доступ к большому, смежно выглядящему блоку памяти, который вам нужен malloc/free для управления им.

Как только ваш процесс имеет доступную ему кучу памяти, все это касается разделения его на куски, причем каждый кусок содержит свою метаинформацию о его размере и позиции и независимо от того, выделен ли он или нет, а затем управление этими фрагментами. Простой список структур, каждый из которых содержит некоторые поля для метаинформации и большой массив байтов, может работать, и в этом случае malloc должен запускаться через список, пока не найдет достаточно большой нераспределенный кусок (или куски, которые он может комбинировать), и затем карту в большем объеме памяти, если он не может найти достаточно большой кусок. Как только вы найдете фрагмент, вы просто возвращаете указатель на данные. free() может затем использовать этот указатель для обратного обращения нескольких байтов к полям-членам, которые существуют в структуре, которые затем могут быть изменены (т.е. marking chunk.allocated = false;). Если в конце списка достаточно нераспределенных фрагментов, вы даже можете удалить их из списка и отменить или сжать эту память с вашей кучи процессов.

Это реальный простой способ реализации malloc. Как вы можете себе представить, существует множество возможных способов разделения вашей памяти на куски, а затем управление этими кусками. Там так много способов, как есть структуры данных и алгоритмы. Все они предназначены для разных целей, например, для ограничения фрагментации из-за небольших выделенных фрагментов, смешанных с небольшими, нераспределенными кусками, или обеспечения того, чтобы malloc и свободный бег быстро (а иногда даже медленнее, но предсказуемо медленно). Там dlmalloc, ptmalloc, jemalloc, Хранить malloc и многое другое, и многие из них довольно маленькие и кратки, поэтому не бойтесь их читать. Если я правильно помню, "Язык программирования C" Кернигана и Ричи даже использует простую реализацию malloc в качестве одного из своих примеров.

Ответ 2

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

Таким образом, нерегулярный вопрос может заключаться в том, как вы планируете создавать malloc() и free() вместо этого, что не является тривиальным вопросом, но вы можете частично ответить на него, предложив некоторую очень простую реализацию пула памяти, который не был бы эквивалентен к malloc(), конечно, но будет указывать на ваше присутствие знаний.

Ответ 3

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

Преимущества в том, что вы можете делать выделение почти в течение постоянного времени, недостатком является то, что ваше приложение потребляет больше памяти, чем нужно.

Ответ 4

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

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

EDIT: как отметил Sharptooth, имеет смысл разрабатывать бесплатно и malloc вместе. Итак, первое, что нужно было бы выяснить, как реализовать malloc.

Ответ 5

Расскажите мне, как вы создадите свою собственную функцию free() для освобождения выделенной памяти.

#include <stdlib.h>
#undef free
#define free(X) my_free(X)

inline void my_free(void *ptr) { }

Как он может быть более эффективным, чем функция C free free()?

Это очень быстро, требуя нуля машинных циклов. Это также приводит к исчезновению ошибок после использования. Это очень полезная функция free для использования в программах, которые создаются как непродолжительные пакетные процессы; его можно с пользой развернуть в некоторых производственных ситуациях.

Что вы можете сделать?

Я действительно хочу эту работу, но в другой компании.

Ответ 6

malloc и free имеют смысл только в том случае, если ваше приложение должно работать поверх ОС. Если вы хотите написать свои собственные функции управления памятью, вам нужно будет знать, как запросить память из этой конкретной ОС, или вы можете зарезервировать память кучи сразу, используя существующий malloc, а затем использовать свои собственные функции для распространения/перераспределения выделенная память через ваше приложение

Ответ 7

Существует архитектура, в которой malloc и free должны придерживаться - по существу, архитектуры класса, позволяющей сосуществовать различные стратегии. Тогда версия бесплатного, которая выполняется, соответствует версии используемого malloc.

Однако я не уверен, как часто наблюдается эта архитектура.

Ответ 8

Знание работы malloc() необходимо реализовать free(). Вы можете найти реализацию malloc() и free() с помощью системного вызова sbrk() в K & R Язык программирования C Глава 8, Раздел 8.7 "Пример - Алокатор хранения" стр. 185-189.