Привет, Хабр! Представляю вашему вниманию перевод статьи « Демистификация управления памятью в современных языках программирования » Дипу К.
Сасидхарана.
В этой серии статей я хотел бы развеять мифы об управлении памятью в программном обеспечении (далее — ПО) и подробно рассмотреть возможности, предоставляемые современными языками программирования.
Надеюсь, что мои статьи помогут читателю заглянуть под капот этих языков и узнать для себя что-то новое.
Углубленное изучение концепций управления памятью позволяет писать более эффективное программное обеспечение, поскольку стиль и практика кодирования оказывают большое влияние на то, как память распределяется для нужд программы.
Часть 1. Введение в управление памятью
Управление памятью — это целый набор механизмов, позволяющих контролировать доступ программы к оперативной памяти компьютера.Эта тема очень важна в разработке программного обеспечения и в то же время вызывает затруднения или даже остается черным ящиком для многих программистов.
Для чего используется ОЗУ?
Когда программа работает в операционной системе компьютера, ей необходим доступ к оперативной памяти (ОЗУ), чтобы:- загрузить свой собственный байт-код для выполнения;
- хранить значения переменных и структур данных, которые используются во время работы;
- загружать внешние модули, необходимые программе для выполнения задач.
Куча
Стек используется для распределения статической памяти.Он организован по принципу «последним пришёл — первым ушёл» ( ЛИФО ).
Вы можете думать о стопке как о стопке книг — вам разрешено взаимодействовать только с самой верхней книгой: читать ее или положить на нее новую.
- Благодаря упомянутому принципу стек позволяет очень быстро выполнять операции с данными — все манипуляции производятся с «верхней книгой в стеке».
Книга добавляется в самый верх, если данные нужно сохранить, или берется сверху, если данные нужно прочитать;
- есть ограничение в том, что данные, которые предполагается хранить в стеке, должны быть конечными и статичными — их размер должен быть известен на этапе компиляции;
- Память стека хранит стек вызовов — информацию о ходе выполнения цепочек вызовов функций в виде кадров стека.
Каждый кадр стека представляет собой набор блоков данных, в которых хранится информация, необходимая для работы функции на определенном шаге — ее локальные переменные и аргументы, с которыми она была вызвана.
Например, каждый раз, когда функция объявляет новую переменную, она добавляет ее в верхний блок стека.
Затем, когда функция завершается, все блоки памяти в стеке, которые использовала функция, очищаются — другими словами, все блоки в ее кадре стека очищаются;
- Каждый поток в многопоточном приложении имеет доступ к собственному стеку;
- Управление стековой памятью простое и понятное; он выполняется операционной системой;
- В стеке обычно хранятся такие данные, как локальные переменные и указатели;
- При работе со стеком существует вероятность получения ошибок переполнения стека, так как его максимальный размер строго ограничен.
Например, ошибка при построении граничного условия в рекурсивной функции наверняка приведет к переполнению стека;
- Большинство языков имеют ограничение на размер значений, которые могут храниться в стеке;
Использование стека в JavaScript. Объекты хранятся в куче, и доступ к ним осуществляется по ссылкам, хранящимся в стеке.
Здесь можно посмотреть в видео формате
Куча
Куча используется для динамического распределения памяти, однако, в отличие от стека, данные в куче сначала нужно найти с помощью «оглавления».Вы можете себе представить, что куча — это такая большая многоуровневая библиотека, в которой, следуя определенным инструкциям, можно найти нужную книгу.
- операции над кучей выполняются несколько медленнее, чем над стеком, так как требуют дополнительного шага поиска данных;
- в куче хранятся данные динамического размера, например список, в который можно добавлять произвольное количество элементов;
- куча является общей для всех потоков приложения;
- Из-за своей динамической природы управлять кучей непросто, и она ответственна за большинство всех проблем и ошибок, связанных с памятью.
Способы решения этих проблем предоставляют языки программирования;
- Типичными структурами данных, хранящимися в куче, являются глобальные переменные (они должны быть доступны различным потокам приложения, а куча является общей для всех потоков), ссылочные типы, такие как строки или ассоциативные массивы, а также другие сложные структуры данных;
- При работе с кучей можно получить ошибки нехватки памяти, если приложение пытается использовать больше памяти, чем ему доступно;
- Размер значений, которые можно хранить в куче, ограничен только общим объемом памяти, который операционная система выделила для программы.
Почему важно эффективное управление памятью?
В отличие от жестких дисков, объем оперативной памяти очень ограничен (хотя и жесткие диски, конечно, не безграничны).Если программа потребляет память, не освобождая ее, в конечном итоге она израсходует все доступные резервы и попытается исчерпать память.
Тогда он просто выйдет из строя сам по себе или, что более драматично, приведет к сбою операционной системы.
Поэтому не рекомендуется легкомысленно относиться к манипуляциям с памятью при разработке программного обеспечения.
Различные подходы
Современные языки программирования стараются максимально упростить работу с памятью и избавить разработчиков от части головной боли.И хотя некоторые почтенные языки по-прежнему требуют ручного управления, большинство из них по-прежнему предоставляют более элегантные автоматизированные подходы.
Иногда в языке используется несколько подходов к управлению памятью, а иногда разработчик может даже выбрать, какой вариант будет более эффективным конкретно для его задач (хороший пример — С++ ).
Перейдем к краткому обзору различных подходов.
Ручное управление памятью
Язык не предоставляет механизмов автоматического управления памятью.Выделение и освобождение памяти для создаваемых объектов остается полностью на усмотрении разработчика.
Примером такого языка является С .
Он предоставляет несколько методов ( маллок , перераспределить , каллок И бесплатно ) для управления памятью — разработчик должен использовать их для выделения и освобождения памяти в своей программе.
Такой подход требует большой осторожности и внимания.
Это также особенно сложно для новичков.
Уборщик мусора
Сбор мусора — это процесс автоматического управления памятью в куче, заключающийся в поиске неиспользуемых областей памяти, ранее занятых потребностями программы.Это один из самых популярных механизмов управления памятью в современных языках программирования.
Процедура сбора мусора обычно запускается через заранее определенные интервалы времени, а иногда выполняется одновременно с ресурсоемкими процессами, что приводит к задержкам в работе приложения.
JVM ( Джава / Скала / классный / Котлин ), JavaScript , Питон , С# , Голанг , OCaml И Рубин — это примеры популярных языков, использующих сборку мусора.
- Сборщик мусора на основе алгоритма тегирования (Mark & Sweep): это алгоритм, который работает в два этапа: сначала он помечает в памяти объекты, на которые имеются ссылки, а затем освобождает память от объектов, не получивших меток.
Этот подход используется, например, в JVM, C#, Ruby, JavaScript и Golang. JVM имеет на выбор несколько различных алгоритмов сборки мусора, а механизмы JavaScript, такие как V8, используют алгоритм маркировки в дополнение к подсчету ссылок.
Такой сборщик мусора может быть включен в C и C++ как внешняя библиотека.
Визуализация алгоритма тегирования: объекты, связанные ссылками, тегируются, а затем удаляются недоступные. - Сборщик мусора с подсчетом ссылок : для каждого объекта в куче ведется счетчик обращений к нему — если счетчик достигает нуля, то память освобождается.
Этот алгоритм в чистом виде не способен корректно обрабатывать циклические обращения объекта к самому себе.
Сборщик мусора с подсчетом ссылок, а также дополнительные приемы для обнаружения и обработки циклических ссылок используются, например.
PHP , Перл И Питон .
Этот алгоритм сборки мусора также можно использовать в С++ ;
Получение ресурса — это инициализация (RAII)
РАИИ — это идиома программирования в ООП, смысл которой заключается в том, что область памяти, выделяемая для объекта, строго привязана к его времени жизни.Память выделяется в конструкторе и освобождается в деструкторе.
Впервые этот подход был реализован в С++ , а также используется в Ада И Ржавчина .
Автоматический подсчет ссылок (ARC)
Этот подход очень похож на сборку мусора с подсчетом ссылок, однако вместо запуска процесса подсчета через определенные интервалы инструкции выделения и освобождения памяти вставляются непосредственно в байт-код во время компиляции.Когда счетчик ссылок достигает нуля, память освобождается в рамках обычного потока выполнения программы.
Автоматический подсчет ссылок по-прежнему не обрабатывает циклические ссылки и требует от разработчика использования специальных ключевых слов для дополнительной обработки таких ситуаций.
АРК это одна из особенностей переводчика Кланг , поэтому присутствует в языках Цель-C И Быстрый .
Автоматический подсчет ссылок также доступен для использования в Ржавчина и новые стандарты С++ С помощью умные указатели .
Владение
Эта комбинация РАИИ с концепцией владения, согласно которой каждое значение в памяти должно иметь только одну переменную-владельца.Когда владелец покидает зону исполнения, память тут же освобождается.
Можно сказать, что это что-то вроде подсчета ссылок на этапе компиляции.
Этот подход используется в Ржавчина мне также не удалось найти какой-либо другой язык, использующий аналогичный механизм.
В этой статье были рассмотрены основные понятия в области управления памятью.
Каждый язык программирования использует свои реализации этих подходов и алгоритмов, оптимизированных для различных задач.
В следующих частях мы подробнее рассмотрим решения по управлению памятью на популярных языках.
Читайте также другие части серии:
- > Часть 1. Введение в управление памятью
- Часть 2. Управление памятью в JVM (Java, Kotlin, Scala, Groovy)
- Часть 3. Управление памятью в V8 (JavaScript/WebAssembly)
- Часть 4. Управление памятью в Go (в разработке)
- Часть 5: Управление памятью в Rust (в разработке)
- Часть 6. Управление памятью в Python (в разработке)
- Часть 7. Управление памятью в C++ (в разработке)
- Часть 8. Управление памятью в C# (в разработке)
Ссылки
- http://homepages.inf.ed.ac.uk
- https://javarevisited.blogspot.com
- http://net-informations.com
- https://gribblelab.org
- https://medium.com/computed-comparisons
- https://en.wikipedia.org/wiki/Garbage*collection*(computer_science)
- https://en.wikipedia.org/wiki/Automatic_Reference_Counting
- https://blog.sessionstack.com
Если вам понравилась статья, пожалуйста, проголосуйте за нее или напишите комментарий.
Вы можете подписаться на автора статьи по адресу Твиттер и дальше LinkedIn .
Иллюстрации: Визуализация стека выполнена с использованием репетитор по Python .
Иллюстрация понятия собственности: Линк Кларк, команда Rust под Лицензия Creative Commons с указанием авторства, версия 3.0 .
Отдельное спасибо за корректуру перевода.
Александр Максимовский И Катерина Шибакова Теги: #программирование #информатика #управление памятью #утечки памяти
-
Курсы Powerpoint На 2 Года
19 Oct, 24 -
Альтернатива Рейтингам. Размышления.
19 Oct, 24 -
Секретный Чип В Наушниках Ipod Shuffle
19 Oct, 24