Графическое выделение памяти в Golang

Go

Выделение памяти для общих программ

Прежде чем говорить о распределении памяти в Golang, давайте взглянем на распределение памяти в общих программах:

Выше приведена логическая классификация памяти программ.

Давайте посмотрим на реальную (настоящую логическую) карту памяти общей программы:

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

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

Основную идею выделения памяти в Go можно разделить на следующие пункты:

  • Каждый раз, когда у операционной системы запрашивается большой кусок памяти, Go выделяет этот кусок памяти, чтобы уменьшить количество системных вызовов.
  • Алгоритм распределения памяти принимает GoogleTCMalloc算法. Алгоритм более сложный, и с принципом можно ознакомиться самостоятельно. Основная идея состоит в том, чтобы разделить память на очень маленькие части и разделить ее на многоуровневое управление, чтобы уменьшить гранулярность блокировок.
  • Когда объектная память освобождается, она на самом деле не освобождается, а помещается обратно в предварительно выделенный большой блок памяти для повторного использования. Только когда память слишком простаивает, она попытается вернуть часть памяти операционной системе, чтобы уменьшить общие накладные расходы.

Структура памяти 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? На самом деле память самой структуры 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互联网技术窝

Вопросы можно оставлять прямо в паблике

использованная литература: