Почему CGO_ENABLE оказывает такое влияние на виртуальную память? - PullRequest
0 голосов
/ 31 января 2019

У меня есть маленький демон, написанный на Golang, который работает в цикле и делает некоторые вещи.Я обнаружил, что демон ведет себя по-разному в случаях, когда он компилируется с CGO_ENABLE = 1 или CGO_ENABLED = 0.Например, при CGO_ENABLE = 1 (по умолчанию) VSZ программы увеличивается до 1-2 ГБ в течение короткого периода времени (в течение часа).При CGO_ENABLED = 0 VSZ одинаков в течение длительного периода времени (в течение нескольких дней).Посмотрите на числа ниже:

CGO_ENABLED = 1 (демон работал 5 минут)

$ grep -E 'VmSize|VmRSS' /proc/14916/status
VmSize:    1084052 kB
VmRSS:       12524 kB

CGO_ENABLED = 0 (демон работал ~ 30 часов)

$ grep -E 'VmSize|VmRSS' /proc/15160/status
VmSize:    110232 kB
VmRSS:       9756 kB

Демон не использует CGO-зависимые пакеты или функции.Другие программы, написанные на Go, демонстрируют такое же поведение.Я знаю разницу между VSZ и RSS и мне интересно, какова природа такого поведения?Почему программа, скомпилированная с CGO_ENABLED = 1, запрашивает столько памяти из ядра?

Я бы предпочел, чтобы ответы были не в форме «не волнуйтесь, VSZ - это просто виртуальная память, и на самом деле она не используется процессом».

1 Ответ

0 голосов
/ 01 февраля 2019

Я мог бы сделать обоснованное предположение.

Как вы, наверное, знаете, компилятор "эталонной" реализации Go (исторически называемый "gc"), который доступен для загрузки с основного сайта) по умолчанию создает статически связанные двоичные файлы.Это означает, что такие двоичные файлы зависят только от так называемых «системных вызовов», предоставляемых ядром ОС, и не зависят от каких-либо общих библиотек, предоставляемых ОС (или сторонними разработчиками).

На платформах на основе Linuxэто не совсем так: в настройках по умолчанию (сборка в Linux для Linux, т.е. не кросс-компиляция) сгенерированный двоичный файл фактически связан с libc и libpthread (косвенно, через libc).

Этот «поворот» вытекает из двух потребностей, с которыми стандартная библиотека Go должна взаимодействовать с ОС:

  1. Разрешение DNS, которое необходимо для пакета net.
  2. Поиск пользователей и групп, необходимый для пакета os.

Проблема здесь двоякая:

  • Linux само по себе (то есть ядро, а не вся ОС) не предоставляет никаких средств для выполнения этих задач.

  • Любая типичная UNIX-подобная система, посколькунавсегда, обеспечивает обе эти задачи, используя специальное средство под названием «NSS», в которомich - это «переключатель службы имен» *.

    NSS предоставляет подключаемые модули, которые могут служить базами данных, предлагающими запросы определенного типа: DNS, базы данных пользователей / групп и т. д. (например, общеизвестныеназвания для "услуг" и т. д.).Предположительно довольно распространенным примером нестандартного поставщика для баз данных пользователей / групп является локальная служба, которая связывается с сервером LDAP.

В типичной ОС на основе GNU / Linux NSSреализован с помощью libc (в менее типичных системах он может быть предоставлен отдельной общей библиотекой, но это не сильно изменится).

Поскольку, как правило, libc довольно стабильная библиотекас точки зрения своего API (он даже предоставляет версионные символы для будущего), авторы Go по праву решили, что при связывании с libc необходимо импортировать минимальное подмножество символов (в основном getaddrinfo, getnameinfo, getpwnam_r и т. д.) нормально делать по умолчанию, поскольку это безопасно в 99% случаев, а когда это не так, те, кто должен заниматься этими делами, обычно знают, что делать в любом случае.

Итак, по умолчанию cgo включен и используется для реализации этих поисков с использованием NSS.

Если cgo отключен, компилятор Go вместо этого ссылается на свои собственные резервные реализации, которые пытаютсяmic - подмножество того, что делает полномасштабная реализация NSS (то есть анализирует /etc/resolv.conf и использует полученную от него информацию для прямого запроса DNS-серверов, перечисленных здесь;парсинг /etc/passwd и /etc/group для обслуживания запросов к базе данных пользователей / групп).

Как вы можете видеть, в случае сбоя

  • libc отображается ви
  • Он инициализирован и использует некоторую память для собственных нужд - например, для очевидного кэширования данных, возвращаемых вызовами NSS.

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

Рассмотрите возможность изучения вывода этого запроса для дополнительного удовольствия; -)


¹ не путать с Mozilla libnss.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...