Что такое фрагментация памяти

Явление фрагментации памяти. Фрагментация памяти, обусловленная методом распределения памяти. Внутренняя и внешняя фрагментация. Методы борьбы с фрагментацией памяти.

Что такое фрагментация памяти. dark fb.4725bc4eebdb65ca23e89e212ea8a0ea. Что такое фрагментация памяти фото. Что такое фрагментация памяти-dark fb.4725bc4eebdb65ca23e89e212ea8a0ea. картинка Что такое фрагментация памяти. картинка dark fb.4725bc4eebdb65ca23e89e212ea8a0ea. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению. Что такое фрагментация памяти. dark vk.71a586ff1b2903f7f61b0a284beb079f. Что такое фрагментация памяти фото. Что такое фрагментация памяти-dark vk.71a586ff1b2903f7f61b0a284beb079f. картинка Что такое фрагментация памяти. картинка dark vk.71a586ff1b2903f7f61b0a284beb079f. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению. Что такое фрагментация памяти. dark twitter.51e15b08a51bdf794f88684782916cc0. Что такое фрагментация памяти фото. Что такое фрагментация памяти-dark twitter.51e15b08a51bdf794f88684782916cc0. картинка Что такое фрагментация памяти. картинка dark twitter.51e15b08a51bdf794f88684782916cc0. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению. Что такое фрагментация памяти. dark odnoklas.810a90026299a2be30475bf15c20af5b. Что такое фрагментация памяти фото. Что такое фрагментация памяти-dark odnoklas.810a90026299a2be30475bf15c20af5b. картинка Что такое фрагментация памяти. картинка dark odnoklas.810a90026299a2be30475bf15c20af5b. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

Что такое фрагментация памяти. caret left.c509a6ae019403bf80f96bff00cd87cd. Что такое фрагментация памяти фото. Что такое фрагментация памяти-caret left.c509a6ae019403bf80f96bff00cd87cd. картинка Что такое фрагментация памяти. картинка caret left.c509a6ae019403bf80f96bff00cd87cd. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

Что такое фрагментация памяти. caret right.6696d877b5de329b9afe170140b9f935. Что такое фрагментация памяти фото. Что такое фрагментация памяти-caret right.6696d877b5de329b9afe170140b9f935. картинка Что такое фрагментация памяти. картинка caret right.6696d877b5de329b9afe170140b9f935. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

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

Появление или непоявление фрагментации зависит от метода организации памяти.

Внутренняя фрагментация – при заполнении страниц в среднем половина последней страницы остаётся незаполненной. Эти «дыры» и есть внутренняя фрагментация.

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

При страничной организации памяти внешняя фрагментация отсутствует, а потери из-за внутренней фрагментации, поскольку процесс занимает целое число страниц, ограничены частью последней страницы процесса.

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

Источник

Что раздувает память в Ruby?

У нас в Phusion работает простой многопоточный HTTP-прокси на Ruby (раздаёт пакеты DEB и RPM). Я видел на нём потребление памяти 1,3 ГБ. Но это безумие для stateless-процесса…

Что такое фрагментация памяти. 9baf7ad2bd3ecdfb0779482c018473eb. Что такое фрагментация памяти фото. Что такое фрагментация памяти-9baf7ad2bd3ecdfb0779482c018473eb. картинка Что такое фрагментация памяти. картинка 9baf7ad2bd3ecdfb0779482c018473eb. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

Вопрос: Что это? Ответ: Использование памяти процессом Ruby с течением времени!

Оказывается, я не одинок в этой проблеме. Приложения Ruby могут использовать много памяти. Но почему? Согласно Heroku и Нейту Беркопеку, в основном раздутие связано с фрагментацией памяти и чрезмерным распределением по кучам.

Беркопек пришёл к выводу, что существует два решения:

Магия — это просто наука, которую мы пока не понимаем. Поэтому я отправился в исследовательское путешествие, чтобы узнать всю правду. В этой статье осветим следующие темы:

Содержание

Распределение памяти в Ruby: введение

Распределение памяти в Ruby происходит на трёх уровнях, сверху вниз:

На своей стороне Ruby организует объекты в областях памяти, называемых страницами кучи Ruby. Такая страница кучи разбита на слоты одинакового размера, где один объект занимает один слот. Будь то строка, хеш-таблица, массив, класс или что-то ещё, он занимает один слот.

Что такое фрагментация памяти. image loader. Что такое фрагментация памяти фото. Что такое фрагментация памяти-image loader. картинка Что такое фрагментация памяти. картинка image loader. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

Слоты на странице кучи могут быть заняты или свободны. Когда Ruby выделяет новый объект, тот сразу пытается занять свободный слот. Если свободных слотов нет, то будет выделена новая страница кучи.

Слот небольшой, около 40 байт. Очевидно, что некоторые объекты в него не поместятся, например, строки по 1 МБ. Тогда Ruby сохраняет информацию в другом месте за пределами страницы кучи, а в слот помещает указатель на эту внешнюю область памяти.

Что такое фрагментация памяти. image loader. Что такое фрагментация памяти фото. Что такое фрагментация памяти-image loader. картинка Что такое фрагментация памяти. картинка image loader. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

Данные, которые не помещаются в слот, хранятся вне страницы кучи. Ruby помещает в слот указатель на эти внешние данные

Как страницы кучи Ruby, так и любые внешние области памяти выделяются с помощью распределителя памяти системы.

Системный распределитель памяти

Распределитель памяти операционной системы является частью glibc (среда выполнения C). Он используется почти всеми приложениями, а не только Ruby. У него простой API:

В свою очередь, распределитель памяти обращается к API ядра. Он забирает из ядра гораздо большие куски памяти, чем запрашивают его собственные абоненты, поскольку вызов ядра дорогостоящий и у API ядра есть ограничение: оно может выделять память только кратно 4 КБ.

Что такое фрагментация памяти. image loader. Что такое фрагментация памяти фото. Что такое фрагментация памяти-image loader. картинка Что такое фрагментация памяти. картинка image loader. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

Распределитель памяти выделяет большие куски — они называются системные кучи — и делит их содержимое для удовлетворения запросов из приложений

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

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

Что такое фрагментация памяти. image loader. Что такое фрагментация памяти фото. Что такое фрагментация памяти-image loader. картинка Что такое фрагментация памяти. картинка image loader. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

Ruby выделяет память из распределителя памяти, который, в свою очередь, выделяет её из ядра

Ядро может выделять память только юнитами по 4 КБ. Один такой блок 4 КБ называется страницей. Чтобы не путать со страницами кучи Ruby, для ясности будем использовать термин системная страница (OS page).

Причину сложно объяснить, но так работают все современные ядра.

Выделение памяти через ядро оказывает значительное влияние на производительность, поэтому распределители памяти пытаются минимизировать количество вызовов ядра.

Определение использования памяти

Таким образом, память выделяется на нескольких уровнях, и каждый уровень выделяет больше памяти, чем ему действительно нужно. На страницах кучи Ruby могут быть свободные слоты, как и в системных кучах. Поэтому ответ на вопрос «Сколько памяти используется?» полностью зависит от того, на каком уровне вы спрашиваете!

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

Что такое фрагментация?

Фрагментация памяти означает, что выделения памяти беспорядочно разбросаны. Это может вызвать интересные проблемы.

Фрагментация на уровне Ruby

Рассмотрим сборку мусора Ruby. Сборка мусора для объекта означает маркировку слота страницы кучи Ruby как свободного, что позволяет его повторно использовать. Если вся страница кучи Ruby состоит только из свободных слотов, то всю её целиком можно освободить обратно в распределитель памяти (и, возможно, обратно в ядро).

Что такое фрагментация памяти. image loader. Что такое фрагментация памяти фото. Что такое фрагментация памяти-image loader. картинка Что такое фрагментация памяти. картинка image loader. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

Но что произойдёт, если свободны не все слоты? Что делать, если у нас много страниц кучи Ruby, а сборщик мусора освобождает объекты в разных местах, так что в конечном итоге остаётся много свободных слотов, но на разных страницах? В такой ситуации у Ruby есть свободные слоты для размещения объектов, но распределитель памяти и ядро продолжат выделять память!

Фрагментация на уровне распределителя памяти

У распределителя памяти похожая, но совсем другая проблема. Ему не нужно освобождать сразу целые системные кучи. Теоретически, он может освободить любую отдельную системную страницу. Но поскольку распределитель памяти имеет дело с выделениями памяти произвольного размера, на системной странице может находиться несколько выделений. Он не может освободить системную страницу, пока не освободятся все выделения.

Что такое фрагментация памяти. image loader. Что такое фрагментация памяти фото. Что такое фрагментация памяти-image loader. картинка Что такое фрагментация памяти. картинка image loader. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

Подумайте, что произойдёт, если у нас есть выделение на 3 КБ, а также выделение на 2 КБ, разбитое на две системные страницы. Если вы освободите первые 3 КБ, обе системные страницы останутся частично заняты и не могут быть освобождены.

Что такое фрагментация памяти. image loader. Что такое фрагментация памяти фото. Что такое фрагментация памяти-image loader. картинка Что такое фрагментация памяти. картинка image loader. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

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

Ещё хуже: что делать, если много свободных мест, но ни одно из них не достаточно велико, чтобы удовлетворить новый запрос на выделение? Распределителю памяти придётся выделить совершенно новую системную кучу.

Является ли фрагментация страниц кучи Ruby причиной раздутия памяти?

Вполне вероятно, что фрагментация является причиной чрезмерного использования памяти в Ruby. Если так, то какая из двух фрагментаций наносит больший вред? Это…

Что такое фрагментация памяти. image loader. Что такое фрагментация памяти фото. Что такое фрагментация памяти-image loader. картинка Что такое фрагментация памяти. картинка image loader. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

ObjectSpace.memsize_of_all возвращает память, занятую всеми активными объектами Ruby. То есть всё место в своих слотах и любые внешние данные. На приведённой выше диаграмме это размер всех синих и оранжевых объектов.

GC.stat позволяет узнать размер всех свободных слотов, т. е. всю серую область на иллюстрации выше. Вот алгоритм:

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

Я написал простую тестовую программу, которая создает кучу потоков, каждый из которых выделяет строки в цикле. Вот какой результат получился через некоторое время:

Что такое фрагментация памяти. image loader. Что такое фрагментация памяти фото. Что такое фрагментация памяти-image loader. картинка Что такое фрагментация памяти. картинка image loader. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

это… просто… безумие!

Результат показывает, что Ruby настолько слабо влияет на общий объём используемой памяти, что не имеет значения, фрагментированы страницы кучи Ruby или нет.

Придётся искать виновника в другом месте. По крайней мере, теперь мы знаем, что Ruby не виновата.

Исследование фрагментации на уровне распределителя памяти

Ещё один вероятный подозреваемый — распределитель памяти. В конце концов, Нейт Беркопек и Heroku заметили, что возня с распределителем памяти (либо полная замена на jemalloc, либо установка магической переменной среды MALLOC_ARENA_MAX=2 ) резко снижает использование памяти.

Давайте сначала посмотрим, что делает MALLOC_ARENA_MAX=2 и почему это помогает. Затем исследуем фрагментацию на уровне распределителя.

Чрезмерное распределение памяти и glibc

Что такое фрагментация памяти. image loader. Что такое фрагментация памяти фото. Что такое фрагментация памяти-image loader. картинка Что такое фрагментация памяти. картинка image loader. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

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

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

Фактически, максимальное количество системных куч, выделенных таким образом, по умолчанию равно количеству виртуальных процессоров, умноженному на 8. То есть в двухъядерной системе с двумя гиперпотоками на каждом получается 2 * 2 * 8 = 32 системные кучи! Это то, что я называю чрезмерным распределением.

Почему множитель по умолчанию такой большой? Потому что ведущий разработчик распределителя памяти — Red Hat. Их клиенты — большие компании с мощными серверами и тонной оперативной памяти. Вышеуказанная оптимизация позволяет повысить среднюю производительность многопоточности на 10% за счёт значительного увеличения использования памяти. Для клиентов Red Hat это хороший компромисс. Для большинства остальных — вряд ли.

Нейт в своём блоге и статья Heroku утверждают, что увеличение числа системных куч увеличивает фрагментацию, и ссылаются на официальную документацию. Переменная MALLOC_ARENA_MAX уменьшает максимальное количество системных куч, выделяемых для многопоточности. По такой логике, она уменьшает фрагментацию.

Визуализация системных куч

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

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

Во-первых, нужно как-то сохранить схему распределения системных куч. Я изучил исходники распределителя памяти и посмотрел, как он внутренне представляет память. Далее написал библиотеку, которая перебирает эти структуры данных и записывает схему в файл. Наконец, написал инструмент, который берёт такой файл в качестве входных данных и компилирует визуализацию в виде изображений HTML и PNG (исходный код).

Что такое фрагментация памяти. image loader. Что такое фрагментация памяти фото. Что такое фрагментация памяти-image loader. картинка Что такое фрагментация памяти. картинка image loader. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

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

Хотя фрагментация остаётся проблемой, но дело не в ней!

Скорее, проблема в большом количестве серого цвета: это распределитель памяти не отдаёт память обратно в ядро!

После повторного изучения исходного кода распределителя памяти оказалось, что по умолчанию он отдаёт в ядро только системные страницы в конце системной кучи, и даже это делает редко. Вероятно, такой алгоритм реализован из соображений производительности.

Волшебный трюк: обрезание

К счастью, я нашёл один фокус. Есть один программный интерфейс, который заставит распределитель памяти освободить для ядра не только последние, а все подходящие системные страницы. Он называется malloc_trim.

Я знал об этой функции, но не думал, что она полезна, потому что в руководстве сказано следующее:

Функция malloc_trim() пытается освободить свободную память в верхней части кучи.

Руководство ошибается! Анализ исходного кода говорит, что программа освобождает все подходящие системные страницы, а не только верхние.

Что произойдёт, если вызывать эту функцию во время сборки мусора? Я изменил исходный код Ruby 2.6, чтобы вызывать malloc_trim() в функции gc_start из gc.c, например:

И вот результаты теста:

Что такое фрагментация памяти. image loader. Что такое фрагментация памяти фото. Что такое фрагментация памяти-image loader. картинка Что такое фрагментация памяти. картинка image loader. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

Вот как всё выглядит в визуализации:

Что такое фрагментация памяти. image loader. Что такое фрагментация памяти фото. Что такое фрагментация памяти-image loader. картинка Что такое фрагментация памяти. картинка image loader. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

Мы видим много белых областей, которые соответствуют системным страницам, освобождённым обратно в ядро.

Заключение

Оказалось, что фрагментация, в основном, ни при чём. Дефрагментация по-прежнему полезна, но основная проблема заключается в том, что распределитель памяти не любит освобождать память обратно в ядро.

К счастью, решение оказалось очень простым. Главное было найти первопричину.

Исходный код визуализатора

Что насчёт производительности?

Производительность оставалась одним из главных опасений. Вызов malloc_trim() не может обходиться бесплатно, а по коду алгоритм работает в линейном времени. Поэтому я обратился к Ною Гиббсу, который запустил бенчмарк Rails Ruby Bench. К моему удивлению, патч вызвал небольшое увеличение производительности.

Что такое фрагментация памяти. 7e511588c662a60e0f8a82556b2e1988. Что такое фрагментация памяти фото. Что такое фрагментация памяти-7e511588c662a60e0f8a82556b2e1988. картинка Что такое фрагментация памяти. картинка 7e511588c662a60e0f8a82556b2e1988. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

Что такое фрагментация памяти. 474c8ef919bf360ecf45f365e1a87ab0. Что такое фрагментация памяти фото. Что такое фрагментация памяти-474c8ef919bf360ecf45f365e1a87ab0. картинка Что такое фрагментация памяти. картинка 474c8ef919bf360ecf45f365e1a87ab0. Фрагментация – процесс появления незанятых участков в памяти (как оперативной, так и виртуальной и на магнитных носителях). Вызвана наличием в каждом виде памяти деления на мелкие единицы фиксированного размера, в то время как объём информации не обязательно кратен этому делению.

Это взорвало мой разум. Эффект непонятный, но новость хорошая.

Источник

Что такое фрагментация памяти?

Я слышал термин «фрагментация памяти», используемый несколько раз в контексте динамического выделения памяти C++. Я нашел несколько вопросов о том, как бороться с фрагментацией памяти, но не могу найти прямого вопроса, который имеет дело с самим собой. Итак:

11 ответов

представьте, что у вас есть «большой» (32 байта) объем свободной памяти:

теперь выделите некоторые из них (5 выделений):

теперь освободите первые четыре распределения, но не Пятый:

теперь попробуйте выделить 16 байт. Ой, я не могу, хотя там почти вдвое больше свободного.

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

в то время как виртуальная память (гораздо больше) может выглядеть так:

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

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

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

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

Что такое фрагментация памяти?

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

Как я могу сказать, является ли фрагментация памяти проблемой для моего приложения? Какая программа наиболее вероятна страдать?

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

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

каковы хорошие общие способы борьбы с фрагментацией памяти?

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

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

предположим для простого примера игрушки, что у вас есть десять байтов памяти:

теперь выделим три трехбайтовых блока, назовем A, B и C:

Теперь освободите блок B:

Теперь, что произойдет, если мы попытаемся выделить четыре байта в блоке D? Ну, у нас есть четыре байт свободной памяти, но у нас нет четыре!—12—>прилежащей байты памяти свободны, поэтому мы не можем выделить D! Это неэффективное использование памяти, потому что мы должны были иметь возможность хранить D, но мы не смогли. И мы не можем переместить C, чтобы освободить место, потому что очень вероятно, что некоторые переменные в нашей программе указывают на C, и мы не можем автоматически найти и изменить все эти значения.

откуда вы знаете, что это проблема? Ну, самый большой признак, что ваша программа виртуальная размер памяти значительно больше, чем объем памяти, который вы фактически используете. В реальном примере у вас будет намного больше десяти байтов памяти, поэтому D будет просто выделен, начиная с байта 9, а байты 3-5 останутся неиспользуемыми, если позже вы не Выделите что-то длиной три байта или меньше.

в этом примере 3 байта не так много, чтобы тратить, но рассмотрим более патологический случай, когда два выделения пары байтов, например, десять мегабайт отдельно в памяти и нужно выделить блок размером 10 мегабайт + 1 байт. Для этого вам нужно попросить у ОС на десять мегабайт больше виртуальной памяти, хотя вам всего на один байт не хватает места.

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

В общем, чем меньше выделений вы делаете, тем меньше вероятность фрагментации памяти. Однако STL справляется с этим довольно эффективно. Если у вас есть строка, которая использует полнота его текущего распределения, и вы добавляете к нему один символ, он не просто перераспределяет его текущую длину плюс один, он двойники ее длина. Это вариант стратегии «пул для частых небольших ассигнований». Строка захватывает большой кусок памяти, чтобы она могла эффективно справляться с повторными небольшими увеличениями размера без повторных небольших перераспределений. Все контейнеры STL на самом деле делают такие вещи, поэтому, как правило, вам не нужно беспокоиться слишком много о фрагментации, вызванной автоматическим перераспределением контейнеров STL.

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

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

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

обновление:
Google TCMalloc: Кэширование Потоков Malloc
Было обнаружено, что это довольно хорошо при обработке фрагментации в длительном процессе.

Я разрабатывал серверное приложение, у которого были проблемы с фрагментацией памяти на HP-UX 11.23/11.31 ia64.

это выглядело так. Был процесс, который делал выделения памяти и освобождения и бежал несколько дней. И даже несмотря на то, что не было утечек памяти, потребление памяти процесса продолжало расти.

Я знаю, что один из способов избежать фрагментации памяти на HP-UX-использовать либо небольшой блок-распределитель, либо использовать MallocNextGen. В RedHat Linux распределитель по умолчанию, похоже, довольно хорошо справляется с выделением большого количества небольших блоков. В Windows есть Low-fragmentation Heap и он адресует проблему большого количества небольших распределений.

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

Теперь, когда obj2 освобождается, у вас есть 120kb неиспользуемой памяти, но вы не можете выделить полный блок 120kb, потому что память фрагментирована.

общие методы, чтобы избежать этого эффекта включают кольцевые буферы и объект, бассейны. В контекст STL, такие методы, как std::vector::reserve() могу помочь.

очень подробный ответ на фрагментацию памяти можно найти здесь.

это кульминация 11 лет фрагментации памяти ответы, которые я предоставлял людям, задававшим мне вопросы о фрагментации памяти в softwareverify.com

когда ваше приложение использует динамическую память, оно выделяет и освобождает куски памяти. В начале все пространство памяти вашего приложения представляет собой один непрерывный блок свободной памяти. Однако, когда вы выделяете и освобождаете блоки разного размера, память начинает получать фрагментированный, т. е. вместо большого смежного свободного блока и ряда смежных выделенных блоков будет смешанный выделенный и свободный блоки вверх. Поскольку свободные блоки имеют ограниченный размер, их трудно повторно использовать. Е. Г. вы можете иметь 1000 байт свободной памяти, но не могу выделить память для 100 байт блока, потому что все свободные блоки не более 50 байт.

другой, неизбежны, но менее проблематичный источник фрагментации заключается в том, что в большинстве архитектур, адреса памяти должны быть соответствие до 2, 4, 8 etc. байтовые границы (т. е. адреса должны быть кратны 2, 4, 8 и т. д.) Это означает, что даже если у вас есть, например, структура, содержащая 3 char поля, ваша структура может иметь размер 12 вместо 3, из-за того, что все поля выровнены по 4-байтовой границе.

Как я могу сказать, является ли фрагментация памяти проблемой для моего приложения? Какая программа, скорее всего, пострадает?

очевидный ответ заключается в том, что вы получаете исключение памяти.

по-видимому, нет хорошего портативного способа обнаружения фрагментации памяти в C++ приложения. См.ответ для получения более подробной информации.

каковы хорошие общие способы борьбы с фрагментацией памяти?

это сложно в C++, так как вы используете прямые адреса памяти в указателях, и у вас нет контроля над тем, кто ссылается на конкретный адрес памяти. Поэтому перестановка выделенных блоков памяти (как это делает сборщик мусора Java) не является опцией.

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

Это супер-упрощенная версия для чайников.

когда объекты создаются в памяти, они добавляются в конец используемой части в памяти.

Если объект, который не находится в конце используемой части памяти, удаляется, что означает, что этот объект находился между 2 другими объектами, он создаст «отверстие».

Это то, что называется фрагментацией.

когда вы хотите добавить элемент в кучу, происходит то, что компьютер должен выполнить поиск места для этого элемента. Вот почему динамические распределения, когда они не выполняются в пуле памяти или с объединенным распределителем, могут «замедлять» работу. Для тяжелого приложения STL, если вы делаете многопоточность, есть клад распределитель или TBB Intel версия.

теперь, когда память фрагментирована, могут произойти две вещи:

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

Что вы должны помнить, так это то, что на 32-битном x86 настольная система, у вас есть весь 2GB памяти, который разделен на 4KB «страницы» (довольно уверен, что размер страницы одинаковый на всех системах x86). Вам придется вызвать некоторую фрагментацию omgwtfbbq, чтобы иметь проблему. Фрагментация действительно является проблемой прошлого, так как современные кучи чрезмерно велики для подавляющего большинства приложений, и есть распространенность систем, которые способны противостоять этому, таких как управляемые кучи.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *