Как в Unix IV malloc() потеряли: Деннис Ритчи написал аллокатор с картами памяти

The lost malloc()

Автор копается в исходниках Unix IV (1973) и находит в каталоге Денниса Ритчи файл malloc.c с функциями malloc() и mfree(), которые работают не с глобальной кучей, а с явными областями памяти — coremap и swapmap. Интерфейс требует передавать карту и размер освобождаемого блока, что даёт изоляцию и контроль над аллокациями. Позже эти функции уступили место привычным malloc()/free(), а макросы new() появились в Unix V8 и, вероятно, повлияли на C++.

Эти функции, очевидно, занимаются (де)аллокацией памяти и являются предшественниками тех, что мы знаем сегодня. Но интерфейсы другие. malloc() получает дополнительный первый аргумент mp (от «map»), и mfree() тоже.
  1. adrian_b

    Автор так и не выяснил, откуда на самом деле SIMULA 67 взяла «new».

    В ноябре 1965 года Ч.А.Р. Хоар опубликовал чрезвычайно влиятельную статью: «Record Handling». Это было предложение по расширению для преемника ALGOL 60.

    Почти все возможности, добавленные в SIMULA 67 по сравнению с её предшественником, языком SIMULA, происходят напрямую из статьи Хоара, за двумя большими исключениями: наследование классов и «виртуальные» процедуры, которые были изобретены создателями SIMULA 67 (Кристен Нюгор и Уле-Йохан Даль) и которые необходимы для объектно-ориентированного программирования.

    Ключевые слова SIMULA 67 «class» и «new» были взяты из статьи Хоара (на самом деле Хоар взял «class» из COBOL 60, где использовалась совсем другая терминология по сравнению с ALGOL 60, и среди многих различий было использование «class» вместо «type», применяемого в ALGOL 60).

    В статье Хоара обсуждалось множество возможностей языков программирования, большинство из которых были новыми, включая определение структурированных типов с конструкторами и деструкторами, размеченные объединения (взятые у Джона Маккарти), перечисления, NULL-указатель и многие другие.

    SIMULA 67 была одним из первых языков, реализовавших многие из предложенных Хоаром возможностей. Другими языками, реализовавшими некоторые из предложенных возможностей, были IBM PL/I, ALGOL 68, а затем пару лет спустя, в 1970-11, Pascal.

    Ключевое слово «new» уже было впервые использовано Никлаусом Виртом, но у Вирта оно имело иное значение, чем у Хоара. Оно объявляло переменную […]

  2. OskarS

    > Мало того, mfree() получает размер объекта, который освобождает, как и должно быть.

    Я всегда считал это одной из самых больших мелких ошибок в истории этой индустрии. Это означает, грубо говоря, что вы вынуждаете аллокатор памяти отслеживать эти размеры, хотя он не должен этого делать. Практически нет разумного случая, когда вызывающий free() не знает размер выделенного блока, так что теперь мы храним эту бухгалтерию дважды: в «пользовательском пространстве» и внутри аллокатора памяти. Ну, подумайте о случаях, когда вы вызываете malloc:

    * Для выделения одного объекта типа T размер — это просто `sizeof(T)`, так что его можно просто передать в free()

    * Для выделения массива объектов размер — это `count * sizeof(T)`, и я не могу вспомнить ни одного случая, когда вы НЕ знаете, чему равен `count`. Либо он статически задан (и тогда это просто константа), либо, если у вас динамически растущий массив, вам нужно отслеживать зарезервированное пространство, чтобы знать, когда перевыделять. В крайнем случае, это нужно для проверки границ.

    * Для кусков сырой памяти вы, предположительно, тоже знаете при освобождении, каков был размер выделенной сырой памяти, по тем же причинам, что и в предыдущем пункте. Просто валяющийся где-то сырой указатель char* без информации о размере — это ужасная практика в C.

    Если вы действительно не знаете размер своего выделения (очень трудно представить, когда это вообще может произойти), вас следует заставить на стороне пользователя отслеживать его каким-то образом, а не перекладывать […]

  3. veltas

    Я не очень разделяю мнение автора, потому что я не в восторге от «арена-аллокаторов» и мне не особо важно, что free не получает размер. Я считаю, что интерфейс был нормальным.

    Кроме того, «арена-аллокаторы» (лет 20 назад это означало что-то другое, так что, думаю, название просто перебрендировали) не так уж хороши: они упрощают некоторые вещи и иногда повышают производительность, но также склонны использовать больше памяти и вызывать больше фрагментации, если не использовать их осторожно. Это одна из многих причин, по которым мы постепенно ушли от старых линейных аллокаторов, а также потому, что нам просто хотелось иметь простой и гибкий интерфейс, скрывающий сложность.

  4. fjfaase

    Системный вызов sbrk в Linux всё ещё доступен, чтобы получить больше кучи от операционной системы. Так что память по-прежнему выделяется линейно и больше никогда не освобождается. Может быть, теперь функции вроде mmap меняют это. Я использовал sbrk, чтобы реализовать malloc для очень ограниченной реализации стандартной библиотеки.

  5. jdw64

    Когда я был студентом колледжа (15 лет назад), я впервые столкнулся с C через «A Book on C», и C показался мне языком, который прост, но реально может многое. Глядя на то, насколько стар этот язык и сколько концепций, уже используемых в современных языках, было опробовано за историю его разработки, это удивляет. Удивительно, что концепции, которые я считал современными техниками сегодня, уже пробовали десятилетия назад — то есть ещё до моего рождения.

    Поразительно, что такой метод, как Bump Allocator, уже пробовали.

    Как старшие программисты смогли всё это сделать? Я просто восхищён.

Ещё за этот день

2026-11-04