Выделение памяти для общих программ
Прежде чем говорить о распределении памяти в Golang, давайте взглянем на распределение памяти в общих программах:
Выше приведена логическая классификация памяти программ.
Давайте посмотрим на реальную (настоящую логическую) карту памяти общей программы:
Основная идея Go о распределении памяти
Go — это язык программирования со встроенной средой выполнения (runtime).Язык программирования со встроенной средой выполнения обычно отказывается от традиционного метода выделения памяти и управляет ею сам. Таким образом, можно выполнять такие операции, как предварительное выделение и создание пула памяти, чтобы избежать проблем с производительностью, вызванных системными вызовами, и предотвратить необходимость системных вызовов при каждом выделении памяти.
Основную идею выделения памяти в Go можно разделить на следующие пункты:
- Каждый раз, когда у операционной системы запрашивается большой кусок памяти, Go выделяет этот кусок памяти, чтобы уменьшить количество системных вызовов.
- Алгоритм распределения памяти принимает Google
TCMalloc算法. Алгоритм более сложный, и с принципом можно ознакомиться самостоятельно. Основная идея состоит в том, чтобы разделить память на очень маленькие части и разделить ее на многоуровневое управление, чтобы уменьшить гранулярность блокировок. - Когда объектная память освобождается, она на самом деле не освобождается, а помещается обратно в предварительно выделенный большой блок памяти для повторного использования. Только когда память слишком простаивает, она попытается вернуть часть памяти операционной системе, чтобы уменьшить общие накладные расходы.
Структура памяти Go
Go выделяет непрерывный участок памяти (виртуальную память) при запуске программы. В целом так:
Размер диапазона и растрового изображения на рисунке будет меняться по мере изменения кучи.
arena
Площадь арены — это то, что мы обычно называем кучей. В куче существует два типа «вещей» в соответствии с двумя измерениями управления и использования:
Один тип представляет собой большой блок памяти, состоящий из нескольких последовательных страниц с точки зрения распределения управления:
spans
Область промежутков может рассматриваться как область, используемая для арены распределения управления (т. е. кучи), упомянутой выше.
Эта область занимаетmspanуказатель,mspanЧто есть, обсудим позже.
Область промежутков используется для указания, какая страница (страница) в области арены принадлежитmspan.
mspanМожно сказать, что это самая основная единица управления памятью в go, но использование памяти все же должно основываться на «объектах».mspanКакая связь с объектом?
На самом деле, «объект» также должен быть помещен вpageв конце концовpageЭто основная единица хранения памяти.
Отложим проблему и посмотрим на выделение объектов и памяти в целом: как показано ниже
Если вы перераспределите «p4», не хватит ли памяти для выделения? Мусора много?
Эта общая ситуация с выделением вызовет фрагментацию памяти, как ее решить?
Он сводится к четырем словам: назначать по требованию. Go делит блоки памяти на 67 типов разного размера, а затем последовательно делит эти 67 типов больших блоков памяти на маленькие блоки (что можно приблизительно понимать как эквивалент разных размеров.page) называетсяspan(непрерывноpage), который упоминается выше на языке gomspan.
span, таким образом решается проблема фрагментации.
Комментарии кода span разных размеров в 67 выглядят следующим образом (текущая версия 1.11):
// class bytes/obj bytes/span objects tail waste max waste
// 1 8 8192 1024 0 87.50%
// 2 16 8192 512 0 43.75%
// 3 32 8192 256 0 46.88%
// 4 48 8192 170 32 31.52%
// 5 64 8192 128 0 23.44%
// 6 80 8192 102 32 19.07%
// 7 96 8192 85 32 15.95%
// 8 112 8192 73 16 13.56%
// 9 128 8192 64 0 11.72%
// 10 144 8192 56 128 11.82%
// 11 160 8192 51 32 9.73%
// 12 176 8192 46 96 9.59%
// 13 192 8192 42 128 9.25%
// 14 208 8192 39 80 8.12%
// 15 224 8192 36 128 8.15%
// 16 240 8192 34 32 6.62%
// 17 256 8192 32 0 5.86%
// 18 288 8192 28 128 12.16%
// 19 320 8192 25 192 11.80%
// 20 352 8192 23 96 9.88%
// 21 384 8192 21 128 9.51%
// 22 416 8192 19 288 10.71%
// 23 448 8192 18 128 8.37%
// 24 480 8192 17 32 6.82%
// 25 512 8192 16 0 6.05%
// 26 576 8192 14 128 12.33%
// 27 640 8192 12 512 15.48%
// 28 704 8192 11 448 13.93%
// 29 768 8192 10 512 13.94%
// 30 896 8192 9 128 15.52%
// 31 1024 8192 8 0 12.40%
// 32 1152 8192 7 128 12.41%
// 33 1280 8192 6 512 15.55%
// 34 1408 16384 11 896 14.00%
// 35 1536 8192 5 512 14.00%
// 36 1792 16384 9 256 15.57%
// 37 2048 8192 4 0 12.45%
// 38 2304 16384 7 256 12.46%
// 39 2688 8192 3 128 15.59%
// 40 3072 24576 8 0 12.47%
// 41 3200 16384 5 384 6.22%
// 42 3456 24576 7 384 8.83%
// 43 4096 8192 2 0 15.60%
// 44 4864 24576 5 256 16.65%
// 45 5376 16384 3 256 10.92%
// 46 6144 24576 4 0 12.48%
// 47 6528 32768 5 128 6.23%
// 48 6784 40960 6 256 4.36%
// 49 6912 49152 7 768 3.37%
// 50 8192 8192 1 0 15.61%
// 51 9472 57344 6 512 14.28%
// 52 9728 49152 5 512 3.64%
// 53 10240 40960 4 0 4.99%
// 54 10880 32768 3 128 6.24%
// 55 12288 24576 2 0 11.45%
// 56 13568 40960 3 256 9.99%
// 57 14336 57344 4 0 5.35%
// 58 16384 16384 1 0 12.49%
// 59 18432 73728 4 0 11.11%
// 60 19072 57344 3 128 3.57%
// 61 20480 40960 2 0 6.87%
// 62 21760 65536 3 256 6.25%
// 63 24576 24576 1 0 11.45%
// 64 27264 81920 3 128 10.00%
// 65 28672 57344 2 0 4.91%
// 66 32768 32768 1 0 12.50%
Скажите, что представляет каждый столбец:
- класс: идентификатор класса, в каждой структуре диапазона есть идентификатор класса, указывающий тип объектов, которые может обрабатывать диапазон.
- bytes/obj: этот класс представляет количество байтов объекта
- bytes/span: количество байтов, которое каждый диапазон занимает в куче, то есть количество страниц * размер страницы.
- объекты: количество объектов, которые могут быть выделены на интервал, то есть (байты/промежутки)/(байты/объект)
- ненужные байты: Фрагментация памяти, создаваемая каждым интервалом, то есть (байты/промежутки)% (байты/объект)
Читайте следующим образом: В качестве примера возьмем span, тип (класс) которого равен 1, размер элемента в span равен 8 байт, сам span занимает 1 страницу, то есть 8K, и всего можно сохранить 1024 объекта.
Внимательные школьники могут обнаружить, что всего существует 66 типов кодов, а также есть специальный диапазон: То есть при появлении объекта размером более 32к будет выделен специальный спан прямо из кучи.Тип (класс) этого специального спана равен 0, и включается только один большой объект.Размер спана определяется размер объекта.
bitmap
Существует несколько видов растровых изображений: растровые изображения стека, данных и bss, и именно об этом я собираюсь поговорить в этот раз.heap bitmaps.
Роль растрового изображения в этом состоит в том, чтобы отметить меткуarena(т.е. куча) объектов. Один должен отметить, есть ли объект по соответствующему адресу, а другой — отметить, был ли объект помечен gc. Функция немного, поэтому,heap bitmapsИспользуйте два бита.
Один байт в области растрового изображения соответствует структуре памяти четырех указателей в области арены следующим образом:
Адрес растрового изображения увеличивается от старшего адреса к младшему адресу.
Макро картинка такая:
arenaОн содержит базовую единицу управления и объекты или сущности, генерируемые при запуске программы.Эти две части соответственноspansиbitmapЭти две области без кучи соответствуют памяти.
Логическая схема выглядит следующим образом:
Компонент управления памятью
Компоненты управления памятью Go в основном включают:mspan,mcache,mcentralиmheap
-
mspanБазовая единица управления памятью, в которой непосредственно хранятся данные. -
mcache: горутина, привязанная к каждой горутине времени выполнения.mcache(В частности, это P в связанной модели параллелизма GMP, поэтому его можно выделить без блокировок.mspan, о чем будет сказано позже),mcacheвыделит пространство памяти, необходимое горутине для запуска (т.е.mspan). -
mcentralдля всехmcacheвырезать резервную копиюmspan -
mheapПредставляет все пространство кучи, занимаемое программой Go. Он также управляет интервалами бездействия и при необходимости запрашивает новую память у операционной системы.
mspan
mspanсказано вышеspansКогда я конкретно упомянул об этом, удобно выделять и использовать блоки памяти в соответствии с размером объекта.Всего их 67 типов, самое главное решить проблему фрагментации памяти, что уменьшает фрагментацию памяти и улучшает использование памяти.mspanПредставляет собой двусвязный список, основные свойства которого показаны на следующем рисунке:mspanэто базовая единица управления памятью в go, см. вышеspansНа самом деле подробное объяснение было сделано в этой статье, поэтому я не буду повторяться здесь.
mcache
Чтобы избежать непрерывной блокировки, когда несколько потоков обращаются к памяти, горутина выделяетspanКэш блоков памяти, этот кешmcache, к которому будет привязана каждая горутинаmcache, нет конкуренции блокировок, когда каждая горутина обращается за памятью.
Как?
Прежде чем говорить, ознакомьтесь с моделью параллельного планирования Go.Если вы еще не знакомы с ней, прочитайте мою статью.Tickets.WeChat.QQ.com/Yes/74, включая BRT Q2T…
Тогда посмотрите на изображение ниже:
В основном это выглядит как на картинке выше. Взгляните на нашуmcacheгде это находится? Прямо на П!
Знайте, почему нет конкуренции блокировок, потому что горутина может быть связана только с одним P во время работы, иmcacheКак раз на P, поэтому не может быть конфликта блокировок.
Посмотрим еще разmcacheКонкретная структура:
Связанный список span в mcache разделен на две группы, одна группа содержит объекты типа указателя, а другая группа — это объекты, не содержащие типа указателя. Почему отдельно?
Это в основном для облегчения GC.Когда выполняется сборка мусора, нет необходимости дополнительно сканировать список объектов, которые не содержат указатели, чтобы увидеть, есть ли ссылки на другие активные объекты (если вы мало знаете о сборщике мусора go, пожалуйста, см. мою статью.Tickets.WeChat.QQ.com/Yes/_Return 0-8 номер 5…).
за<=32kобъект, который будет передан непосредственно черезmcacheраспространять.
Здесь, я думаю, необходимо рассказать о классификации предметов в го по размерному измерению. Делится на три категории:
- жестяные выделения (размер
- small allocations (16 bytes < size <= 32k)
- large allocations (size > 32k)
Первые две категории:tiny allocationsиsmall allocationsнепосредственно черезmcacheбыть выделенным.
заtiny allocationsраздача, есть микродозаторtiny allocatorДля выделения выделенные объекты не содержат указателей, таких как некоторые небольшие строки и независимые escape-переменные, не содержащие указателей.
small allocationsраспределениеmcacheВ соответствии с размером объекта, чтобы найти размер собственного существования, чтобы соответствоватьmspanвыделить.
когдаmcachКогда нет свободного места,mcentralизmspansСписок, чтобы получить новую спецификацию желаемого размераmspan.
mcentral
для всехmcacheпредоставить нарезанныйmspan.
каждыйmcentralсохранить определенный тип глобальногоmspanСписок, как назначенных, так и неназначенных.
все еще помнюmspanиз 67 типов? Сколько типов естьmspanКак многоmcentral.
каждыйmcentralбудет содержать обаmspanСписок:
- нет свободных объектов или
mspanБылmcacheкэшированныйmspanСписок (пустой mspanList) - с бесплатными объектами
mspanСписок (пустой mspanList)
так какmspanявляется глобальным и будет использоваться всемиmcacheдоступ, поэтому будут проблемы с параллелизмом, поэтомуmcentralБудет замок.
не замужемmcentralСтруктура выглядит следующим образом:
Если вам нужно выделить память,mcentralнет свободного времениmspanсписок, вам нужноmheapполучить.
mheap
mheapЕго можно представить как все пространство кучи, занимаемое программой Go.mheapГлобально уникальная, она может рассматриваться как глобальная переменная.
Его структура выглядит следующим образом:
mheapВ дополнение к вышеупомянутомуmcacheвсе кромеmcacheОн существует в модели планирования P of Go GMP, о которой упоминалось выше.Чтобы узнать о модели параллелизма GMP, вы можете обратиться к моей статье.Tickets.WeChat.QQ.com/Yes/74, включая BRT Q2T…Если присмотреться, то можно найтиmheapВ замке тоже есть замок. Какова функция этого замка?
Мы знаем, что объекты размером более 32 КБ определяются как большие объекты непосредственно черезmheapраспространять. Заявки на эти крупные объекты делаютсяmcacheвыпущено, иmcacheНа P во время работы программы часто бывает несколько P. Следовательно, это приложение памяти является параллельным, поэтому для обеспечения потокобезопасности должна быть глобальная блокировка.
Если требуется выделенная память,mheapЕсли страниц больше нет, то обратиться к операционной системе за новой серией страниц (минимум 1Мб).
Краткое описание процесса выделения памяти Go
Существует три типа объектов:
- крошечные объекты, размер
- Общие небольшие объекты, 16 байт
- Размер большого объекта > 32 КБ
Существует три метода распространения:
- крошечные выделения (размер
- малые выделения (размер
- большие выделения (размер > 32 КБ) выделения больших объектов, передать напрямую
mheapраспространять. Применение этих больших объектов осуществляется за счет глобальной блокировки, поэтому только один P может подать заявку на это в любой момент времени.
Распределение объекта:
- Объекты, размер которых находится в диапазоне ( size mcacheраспределение микродозатором на
- Диапазон размеров (0
- Диапазон размеров (16B
- диапазон размеров в (размер > 32 КБ): выделение больших объектов
Порядок распределения:
- Во-первых, рассчитав используемую спецификацию размера.
- затем используйте
mcacheВыделение блока в соответствующей спецификации размера. - если
mcentralнет доступных блоковmheapПодать заявку и найти наиболее подходящий по алгоритмуmspan. - Если подать заявку на
mspanЕсли размер приложения превышен, оно будет разделено в соответствии с потребностями, чтобы вернуть количество страниц, требуемое пользователем. Остальные страницы образуют новый mspan, который возвращается в список свободных mheap. - Если в mheap нет доступных диапазонов, запросите новый набор страниц (минимум 1 МБ) из операционной системы.
Управление памятью в Go очень сложное, и каждая версия имеет небольшие изменения. Здесь я говорю только о вещах, которые легче всего понять макроскопически. Надеюсь, вы выскажете больше мнений. Если у вас есть какие-либо вопросы, пожалуйста, свяжитесь со мной вовремя. Вот контактные данные:
Пожалуйста, обратите внимание на мой публичный аккаунт WeChat互联网技术窝
использованная литература:
- Распределение программ в памятиБлог Woo Woo.cn на.com/Lynn-Zhang/…
- Начните с выделения памятиБилеты.WeChat.QQ.com/Yes/E-W KF Ru1 маленький…
- Перевод: наглядное руководство по распределителю памяти Gowoohoo.linuxhow.com/go-memory-ahhh…
- Графическое выделение памяти Gonuggets.capable/post/684490…
- Изучение исходного кода Golang (3) Принцип реализации GCБлог Woo Woo.cn на.com/ZK Web/Fear/788…
- Простая и понятная интерпретация принципа распределения памяти в GoОсобенно Aliyun.com/articles/65…
- Дождевые метки >
- перейти к распределению памяти (англ.)Андре STC.com/post/go-what...