LINUX.ORG.RU
Ответ на: комментарий от firkax

Ага, это из-за библиотек фф занимает 2.6гб виртуальной памяти при 700мб физической.

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

annulen ★★★★★
()
Ответ на: комментарий от ezus

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

firkax ★★★★★
()
Ответ на: комментарий от wandrien

Элементарный MAP_PRIVATE основан на CoW. Читай документацию.

Знаю, проверял. В Haiku этот вызов по умолчанию резервирует всю необходимую память и возвращается с ошибкой если памяти не хватает. Для включения overcommit есть специальный флаг MAP_NORESERVE. При исчерпании памяти с включённым overcommit будет не OOM kill, а SIGSEGV, который можно обработать.

X512 ★★★★★
()
Ответ на: комментарий от X512

posix_spawn() уже научился передавать нужные параметры дочернему процессу (POSIX_SPAWN_SETSID и т.п.).

Этого все равно недостаточно. Плюс далеко не все следят за новинками posix_spawn - есть уже написанны код на fork, он работает (в т.ч. и на старых системах) и всех устраивает

annulen ★★★★★
()
Ответ на: комментарий от ezus

Тогда настроить должен системный администратор того компа, на котором она запускается. Ну ладно, какие-нить дефолты можно предусмотреть. Например смотреть в колонку available вывода free и останавливаться, если там меньше 10% от объёма физической памяти.

firkax ★★★★★
()
Ответ на: комментарий от X512

Посмотрел nginx. Для порождения процессов используется подход «fork - настроечный код - exec», который я описывал выше. Ни одного вхождения posix_spawn я не нашел

annulen ★★★★★
()
Последнее исправление: annulen (всего исправлений: 1)
Ответ на: комментарий от firkax

Зачем резервировать память которая не нужна?

Чтобы радикально уменьшить количество аллокаций и таким образом улучшить производительность

annulen ★★★★★
()
Последнее исправление: annulen (всего исправлений: 1)
Ответ на: комментарий от annulen

Ну значить поленились применить posix_spawn(). Суть в том, что fork+exec = posix_spawn, а fork без exec сейчас мало применения. В основном старые утилиты идущие корнями в UNIX и не требующие большой производительности.

X512 ★★★★★
()
Ответ на: комментарий от X512

fork+exec = posix_spawn

Да, но fork+код+exec это намного больше, чем posix_spawn, и многопроцессные приложения вроде nginx и браузеров этим активно пользуются. Плюс даже «тупой» fork+exec, который кто-то «забыл» (на самом деле, даже не планировал) заменить должен работать с нормальной скоростью

annulen ★★★★★
()
Ответ на: комментарий от X512

Нет, posix_spawn это vfork+exec. Он через них реализован.

В основном старые утилиты идущие корнями в UNIX и не требующие большой производительности.

fork() это не то место, где производительность меряется.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от firkax

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

annulen ★★★★★
()
Ответ на: комментарий от X512

Ты наверно опять про vfork. А в тех реализациях возможно к нему (в нарушение стандартов и с опасностью что-то сломать) сделали алиас от fork. Вот наоборот (vfork алиас к настоящему fork) можно без опасений, только чуть медленнее будет.

firkax ★★★★★
()
Ответ на: комментарий от annulen

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

firkax ★★★★★
()
Ответ на: комментарий от annulen

Чтобы форкнуть воркер от мастера, нужно сделать fork(), и затем ещё setgroups/setgid/setuid. Никаких exec-ов там не нужно. exec нужен если у нового процесса другой бинарник, или если хотим от нового процесса надёжно спрятать секретные данные его родителя (очистить память разом без exec затруднительно). Скорее всего ты там exec увидел для обновления бинарника на новую версию или в каком-нить модуле который внешние бинарники запускает.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Походе ты прав, и все действительно так. Но clang в аналогичной ситуации ничтоже сумняшеся делет exec, чисто для удобства передачи другого набора аргументов «внутренней» версии фронтенда.

annulen ★★★★★
()
Ответ на: комментарий от firkax

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

Ещё чтобы память процесса не разрослась в два раза без на то надобности. exec() освобождает память.

X512 ★★★★★
()
Ответ на: комментарий от ezus

А как mmap реагирует на нехватку памяти?

Он присоединяет страницы к адресному пространству процесса. Пустые страницы физическую память не занимают, неиспользуемые могут сбрасываться в своп (в случае анонимных маппингов) или просто выкидываются (в случае файловых маппингов, которые включают в себя и весь исполняемый код). При записи в выделенные страницы или при обращении к коду или данных замапленных файлов страницы оказываются в физической памяти и могут создать cache pressure. Тогда ядро начинает просматривать кэш на предмет того, что можно выкинуть или засвопить. Если дело становится туго, начинаются репрессии через oom killer.

annulen ★★★★★
()
Ответ на: комментарий от ezus

В качестве одного из вариантов решения вашей задачи можно предложить выделить память через mmap и самостоятельно отслеживать момент, когда пора остановиться. Делать это можно разными способами с разной степенью надежности.

  1. Считывать во время выполнения данные о расходе памяти приложением (RSS, VmSize или размер кучи - смотря что лучше подходит) и сравнивать с предварительно рассчитанным лимитом (т.е. сделать «внутренний» аналог системных лимитов
  2. Отслеживать сигналы от ядра через /sys/fs/cgroup/memory/memory.pressure_level или фичи от CONFIG_PSI (зависит от конфигурации ядра, это все отключаемое)
  3. Взять готовый «юзерспейсный oom-killer» и настроить под себя (например, https://github.com/facebookincubator/oomd/ работает через CONFIG_PSI)
annulen ★★★★★
()
Ответ на: комментарий от iliyap

Чтобы не было пейджфолтов надо выделять память с MAP_POPULATE и не форкаться.

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

annulen ★★★★★
()
Ответ на: комментарий от X512

Уже давно нет. Времена когда Apache делал fork при обработке каждого нового соединения давно прошли.

А что насчёт времён, когда создаётся куча потоков и каждый в теории может уйти в глубокую рекурсию и забить этим стек? Оно прошло или только начинается?

khrundel ★★★★
()
Ответ на: комментарий от ezus

Давайте представим, что вот реально вы отключили оверкоммит. Программа начинает просить у системы куски по нескольку мегабайт пока не получит null. Что произойдёт?

Сначала израсходуется вся свободная память. Потом сбросятся кэши дисков. Потом забьётся своп и сбросятся данные в mmap-файлы (или не сбросятся, при отсутствии оверкоммита хз как это всё будет работать), потом в конце концов malloc вернёт null. Вопрос такой, хотите ли вы продолжать работать в системе, в которой памяти вообще не осталось и любая попытка любого работающего процесса выделить память или создать поток или запустить ещё 1 процесс приведёт к неудаче? Далее начинаются хитрые идеи типа вернуть пару последних блоков системе, но free их имеет право не возвращать, а оставить в своём свободном хипе, поэтому надо что-то колхозить, например перед началом аллокации создать процесс, который выделит сколько-то памяти и заснёт, а потом, когда родительский процесс сожрёт всю память нужно будет прибить этот дочерний и таким образом вернуть системе минимум для работы, надеясь что за это время никто другой уже не успел зафейлить что-то важное. В общем получается колхоз ещё хуже чем просто смотреть свободную память перед выделением следующего блока.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

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

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

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

Зачем так костылить, если можно выделить резервную виртуальную память в своём процессе?

X512 ★★★★★
()
Ответ на: комментарий от X512

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

Может и будет, в том плане что программа насрёт в лог и завершится. Насколько это корректно для системы вцелом я не знаю. А если программа - демон, то её инит перезапустит, она пройдёт процесс инициализации, начнёт собирать данные (например перебирать файлы в директории) и в какой-то момент снова упадёт, ведь дефицит памяти никуда не делся.

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

Зачем так костылить, если можно выделить резервную виртуальную память в своём процессе?

Тебе в алгоритме «выделяем память пока можем» костылём кажется только момент с прибитием чайлда?

Всё предельно просто. Про возможность mmap/munmap для возврата памяти системе я как-то не подумал, потому что вообще под юникслайк не писал ничего сложнее лабораторок и пары прикладных проектов, в которых таким не балуются. Форки в лабораторках делал, а маппинг - нет. Но даже отказ от форка не сделает этот подход менее всратым. Т.е. если твой софт может жрать неограниченный объём памяти, ну можно ему в командной строке лимит передавать или там в конфиге. Или, если хочется приключений, можно в конфиге писать минимальный объём свободной в мегабайтах или в процентах, а выделяемый размер уже как-то самому определять. Но вот так тупо выделять пока дают - это уж совсем ни в какие ворота. И наверное даже хорошо что система с оверкоммитом прибивает такие программы, им жить незачем.

khrundel ★★★★
()

у меня пристреливается както так, с какого момента трансмиссия начала течь по памяти…

мар 09 19:54:58 srv16 systemd[1]: transmission-daemon.service: A process of this unit has been killed by the OOM killer.
мар 09 19:54:58 srv16 systemd[1]: transmission-daemon.service: Main process exited, code=killed, status=9/KILL
мар 09 19:54:58 srv16 systemd[1]: transmission-daemon.service: Failed with result 'oom-kill'.
мар 09 19:54:58 srv16 systemd[1]: transmission-daemon.service: Consumed 4min 57.708s CPU time.
мар 09 19:54:59 srv16 systemd[1]: transmission-daemon.service: Scheduled restart job, restart counter is at 181.
pfg ★★★★★
()
Последнее исправление: pfg (всего исправлений: 1)
Ответ на: комментарий от vbr

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

Всё дело в том, что g_malloc() не возвращает NULL, а сразу делает abort(). А на g_malloc() завязано практически всё через зависимости на glib2.

wandrien ★★
()