Ручное управление памятью - Manual memory management

В Информатика, ручное управление памятью относится к использованию программистом ручных инструкций для идентификации и освобождения неиспользуемых объектов, или мусор. Вплоть до середины 1990-х годов большинство языки программирования используется в промышленности, поддерживается ручное управление памятью, хотя вывоз мусора существует с 1959 года, когда он был представлен с Лисп. Однако сегодня языки со сборкой мусора, такие как Ява становятся все более популярными, а языки Цель-C и Быстрый обеспечить аналогичные функции через Автоматический подсчет ссылок. Основными языками с ручным управлением, которые все еще широко используются сегодня, являются C и C ++ - видеть Распределение динамической памяти C.

Описание

Все языки программирования используют ручные методы, чтобы определить, когда выделить новый объект из бесплатного магазина. C использует маллок функция; C ++ и Java используют новый оператор; и многие другие языки (например, Python) выделяют все объекты из бесплатного хранилища. Определение того, когда объект должен быть создан (создание объекта ) обычно тривиален и не вызывает проблем, хотя такие методы, как пулы объектов означают, что объект может быть создан перед немедленным использованием. Настоящая проблема - это разрушение объекта - определение того, когда объект больше не нужен (т. Е. Мусор), и организация возврата его базового хранилища в бесплатное хранилище для повторного использования. При ручном выделении памяти это также указывается вручную программистом; с помощью таких функций, как свободный() в C, или Удалить оператор в C ++ - это контрастирует с автоматическим уничтожением объектов, содержащихся в автоматические переменные, особенно (нестатический) локальные переменные функций, которые уничтожаются в конце своей области видимости в C и C ++.

Ручное управление и корректность

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

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

Языки, которые используют исключительно вывоз мусора как известно, избегают двух последних классов дефектов. Утечки памяти все еще могут происходить (и ограниченные утечки часто возникают при поколенческой или консервативной сборке мусора), но обычно менее серьезны, чем утечки памяти в ручных системах.

Приобретение ресурсов - это инициализация

У ручного управления памятью есть одно преимущество правильности: оно позволяет автоматически Управление ресурсами через Приобретение ресурсов - это инициализация (RAII) парадигма.

Это возникает, когда объекты имеют дефицитный системные ресурсы (например, графические ресурсы, дескрипторы файлов или соединения с базой данных), от которых необходимо отказаться при уничтожении объекта - когда время жизни владения ресурсом должно быть привязано к времени жизни объекта. Языки с ручным управлением могут организовать это путем получения ресурса во время инициализации объекта (в конструкторе) и освобождения во время уничтожения объекта (в деструктор ), который происходит в точное время. Это известно как инициализация получения ресурсов.

Это также можно использовать с детерминированными подсчет ссылок. В C ++ эта возможность используется в дальнейшем для автоматизации освобождения памяти в рамках ручной среды, использующей shared_ptr шаблон в стандартной библиотеке языка для управления памятью - это обычная парадигма. shared_ptr является нет однако подходит для всех моделей использования объектов.

Этот подход неприменим в большинстве языков со сборкой мусора - в частности, для отслеживания сборщиков мусора или более продвинутого подсчета ссылок - из-за того, что завершение не является детерминированным, а иногда и не происходит вообще. То есть трудно определить (или определить), когда или нет финализатор метод может быть вызван; это широко известно как проблема финализатора. Java и другие языки с GC часто используют ручное управление для ограниченных системных ресурсов Помимо память через шаблон утилизации: ожидается, что любой объект, который управляет ресурсами, будет реализовывать утилизировать () , который освобождает любые такие ресурсы и отмечает объект как неактивный. Ожидается, что программисты вызовут утилизировать () вручную по мере необходимости, чтобы предотвратить «утечку» ограниченных графических ресурсов. В зависимости от финализировать () метод (как Java реализует финализаторы) для освобождения графических ресурсов широко рассматривается как плохая практика программирования среди Java-программистов, и аналогичный __del __ () в Python нельзя полагаться на высвобождение ресурсов. Для ресурсов стека (ресурсы, полученные и выпущенные в одном блоке кода) это можно автоматизировать с помощью различных языковых конструкций, таких как Python с, C # с помощью или Java пытаться-с-ресурсами.

Спектакль

Многие сторонники ручного управления памятью утверждают, что оно обеспечивает лучшую производительность по сравнению с автоматическими методами, такими как вывоз мусора. Традиционно задержка была самым большим преимуществом, но теперь это не так. Ручное выделение часто лучше местонахождение ссылки.[нужна цитата ]

Также известно, что ручное выделение больше подходит для систем, в которых память является ограниченным ресурсом из-за более быстрого восстановления. Системы памяти могут и часто "ломаются", поскольку размер программы рабочий набор приближается к размеру доступной памяти; неиспользуемые объекты в системе со сборкой мусора остаются в невосстановленном состоянии дольше, чем в системах с ручным управлением, поскольку они не восстанавливаются немедленно, что увеличивает эффективный размер рабочего набора.

Ручное управление имеет ряд документально подтвержденных характеристик недостатки:

  • Звонки в Удалить и такие накладные расходы возникают каждый раз, когда они создаются, эти накладные расходы могут быть амортизированы за счет циклов сборки мусора. Это особенно верно для многопоточных приложений, в которых вызовы удаления должны быть синхронизированы.
  • Процедура распределения может быть более сложной и медленной. Некоторые схемы сборки мусора, например, с куча compaction, может поддерживать свободное хранилище как простой массив памяти (в отличие от сложных реализаций, требуемых схемами ручного управления).

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

Выделение вручную не страдает от длительных «пауз», которые возникают при простой остановке сборки мусора, хотя современные сборщики мусора имеют циклы сбора, которые часто незаметны.

Ручное управление памятью и сборка мусора страдают от потенциально неограниченного времени освобождения - ручное управление памятью, потому что освобождение одного объекта может потребовать освобождения его членов, рекурсивно его членов и т. Д., В то время как сборка мусора может иметь длинные циклы сборки. Это особенно актуально для реальное время системы, в которых неограниченные циклы сбора, как правило, недопустимы; Сборка мусора в реальном времени возможна путем приостановки сборщика мусора, в то время как для ручного управления памятью в реальном времени требуется избегать больших освобождений или вручную приостанавливать освобождение.

Рекомендации

  • Berger, E.D .; Zorn, B.G .; МакКинли, К.С. (Ноябрь 2002 г.). «Пересмотр пользовательского распределения памяти» (PDF). Материалы 17-й конференции ACM SIGPLAN по объектно-ориентированному программированию, системам, языкам и приложениям. С. 1–12. CiteSeerX  10.1.1.119.5298. Дои:10.1145/582419.582421. ISBN  1-58113-471-1.

внешняя ссылка