LINUX.ORG.RU

C++. Предсказуемость поведения менеджера памяти.


0

1

Проверять результат выполнения new/malloc и т.п. - это конечно полезно, но не так прикольно. Не переключайте канал!

Софтина изредка в несколько потоков вызывает new(), прося что-то в районе 1...2 МБ памяти. Подобные запросы случаются одновременно из 4 потоков. Результат вызова не проверяется. Железных ядер - 4 (на всех нижеописанных платформах).

На тестовой платформе с linux 3.4.9 с 32 Гб ОЗУ работала безупречно.

На тестовой платформе с win-7 с 16 Гб ОЗУ иногда валилась. Валилась с одинаковой вероятностью и на виртуалке с 4 Гб ОЗУ.

Казалось бы - 16 гигов! Параллельно фотошопов не загружено. Если смотреть на стандартный «график использования ресурсов», то уровень занятости памяти валяется в нижних 20%.

Почему может так происходить, что при наличии кучи свободной памяти изредка происходят такие обломы? Ясно, что в таком топике на форуме невозможно объяснить и понять логику такой хитрой штуки, как менеджер памяти какой-либо ОС. Но хотя-бы какими его свойствами это может объясняться? Какие причины гипотетически тут могут быть? Он работает асинхронно от вызовов выделения памяти? Вызов на выделение памяти не блокирующий и может произойти в «неудобное время» (идёт процесс переупорядочения свободных блоков) и будет отклонён? Занятость диспетчера памяти своими служебными задачами рассматривается как отказ, равнозначный отсутствию свободной памяти? Почему вызывающий поток не будет заблокирован, чтобы дождаться окончания служебных процедур, если они кратковременные?

А оно точно на выделении памяти падает-то?

anonymous
()

менеджер памяти какой-либо ОС

new()

/0 и ЛПП.

Чем и в чем собираешь программу под винду? MSVC, минг, цыгвынь?

geekless
()

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

ilovewindows
()

Перечитал первое предложение, сначала глазам не поверил.

Софтина изредка в несколько потоков вызывает new(), прося что-то в районе 1...2 МБ памяти. Подобные запросы случаются одновременно из 4 потоков. Результат вызова не проверяется.

Но теперь таки поверил. Вы что, реально проверяете *возвращаемое значение* оператора new? Или используете его специальную форму, которая не кидает исключений?

yoghurt
()

На тестовой платформе с linux 3.4.9 с 32 Гб ОЗУ работала безупречно.

На тестовой платформе с win-7 с 16 Гб ОЗУ иногда валилась. Валилась с одинаковой вероятностью и на виртуалке с 4 Гб ОЗУ.

Валилась с одинаковой вероятностью и на виртуалке с 4 Гб ОЗУ.

Так а на каком месте валилась то?

yoghurt
()

у меня была ситуация на хостинге на агаве, когда нельзя было выделить больше чем 143 мб на VPS с 256 мб. причем память была, лимиты выбраны не были. алсо, выделение через new работало с большим объемом O_o

ckotinko
()

Результат вызова не проверяется.

ну так проверь в дебаге, в чем проблема то?

AF
()

Почему ты описываешь поведение программы как блондинка? Не «иногда валилась», а будь добр хотя бы написать что это (исключение? segfault?) и показать backtrace. Не можешь - иди борщ варить, нечего тебе за компьютером делать.

И нет, проверять результат выполнения new не нужно - без nothrow он либо кидает исключение, либо всегда возвращает корректный указатель. И нет, ты даже близко не понимаешь как работает менеджер памяти, начиная от его связи (на самом деле, её отсутствия) с ОС и заканчивая домыслами о занятости и асинхронности, так что даже не думай на него грешить - с таким уровнем вывод очевидный и очень простой - у тебя просто кривой код. Начни с запуска его под valgrind, он отловит большинство случаев неправильной работы с памятью.

slovazap
()

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

Да, падает на попытке выделения 1...2 Мб с исключением bad_alloc. Под «значение проверяется» имелся ввиду общий смысл проверки результата выполнения операции выделения памяти - либо возвращаемое значение, либо отсутствие исключений и т.п. В моём случае - кидается исключение из оператора new внутри функции reserve() внутри функции resize() внутри std::vector при попытке сделать resize() на 1...2 Мб.

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

kiverattes
() автор топика
Ответ на: комментарий от geekless

64, но вряд-ли это влияет на суть вопроса. Даже при 32 и при 3 свободных гигах меня бы удивляло, почему нельзя выделить 1...2 Мб.

kiverattes
() автор топика
Ответ на: комментарий от kiverattes

Из-за фрагментации, например. Но в данном случае не похоже.

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

Ну сделай собственный аллокатор, который просит память через VirtualAlloc, и гоняй тесты. Хоть понятно будет, ядро память не даёт или крестовая библиотека.

geekless
()
Ответ на: комментарий от vazgen05

Нет, я ведь написал - проблема в выделении памяти (кидается bad_alloc из new()), а не в access violation или SIGSEGV каком-нибудь.

kiverattes
() автор топика
Ответ на: комментарий от geekless

Это немного не то, что хотелось обсудить в топике. Хотелось обсудить «почему так», а не «как лечить». Как лечить - тыща способов, лежащих на поверхности )

kiverattes
() автор топика

Если бы ты на сях писал, то знал бы, что даже если malloc вернет тебе !NULL, это еще не значит, что тебе действительно дали столько памяти, сколько нужно. А вот если ты ей сделаешь memset(mem, 0, size), и это пройдет без проблем, то все ОК. Кстати, вполне возможно, что с calloc работа упрощается, поэтому им и пользуюсь, в макросе (который проверяет, не было ли ошибок).

А еще полезно вместо free(mem) использовать макрос, который не только освобождает память, но и делает mem = NULL, чтобы где-нибудь дальше ты не имел возможности сделать повторный free()

Anon
()
Ответ на: комментарий от kiverattes

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

Это С++, детка ☺

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

Разве malloc может выделить памяти меньше, чем просили и вернуть на неё указатель? Какой-то бред. Зачем это вообще сделано? Как пользователю этим пользоваться?

kiverattes
() автор топика
Ответ на: комментарий от kiverattes

Может. Ведь тебе дают виртуальную память, а реальной она становится лишь при обращении. Так что, пока ты по всему массиву выделенной памяти не пройдешься, ты не можешь сказать точно, что она у тебя есть. И это правильно, иначе вся память быстренько бы кончилась — всякое УГ, вроде хромых, сожрало бы ее моментально!

Anon
()
Ответ на: комментарий от kiverattes

Разве malloc может выделить памяти меньше, чем просили и вернуть на неё указатель? Какой-то бред. Зачем это вообще сделано? Как пользователю этим пользоваться?

Ты не знаком с устройством unix.

google overcommit

geekless
()
Ответ на: комментарий от d_a

Я же и сказал:

вполне возможно

Потому как лень мне подробности читать. Я думал, что calloc делает после выделения памяти memset

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

Память виртуальная, но если ОС тебе её выделила, то она должна убицца, но в крайнем случае начать юзать своп при обращении к этой памяти. А говорить о том, что часть выделенной памяти (особенно виртуальной) вдруг станет не моей и я получу SEGSEGV - это какой-то бред )

kiverattes
() автор топика

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

Вообще он блокирующий. Вендовое crt (malloc) дёргает HeapAlloc и в качестве флагов передаёт ему 0, что означает, что сериализация не отключена. Так по крайней мере в микрософтовском crt.

Вопрос, чем ты конпиляешь под венду?

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

Ну так если тебе не нравится, ставь vm.overcommit_memory в 2 (/etc/sysctl.conf)

Но в этом случае тебе и 32ГБ оперативы может оказаться мало!

Anon
()
Ответ на: комментарий от kiverattes

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

В линуксе можно выключить оверкоммит.

В BSD вроде бы нельзя.

В винде по умолчанию нет оверкоммита, можно ли его специально включить — не знаю, но думаю, что нет.

geekless
()
Последнее исправление: geekless (всего исправлений: 2)
Ответ на: комментарий от Anon

Но в этом случае тебе и 32ГБ оперативы может оказаться мало!

ЛПП, у меня на десктопе 4 ГБ ОЗУ и 8 свопа. Оверкоммит выключен.

geekless
()
Ответ на: комментарий от kiverattes

А говорить о том, что часть выделенной памяти (особенно виртуальной) вдруг станет не моей и я получу SEGSEGV - это какой-то бред )

А если представить себе типичную unix-машину и подумать?

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

Я на 2ГБ оверкоммит отключал, но это приводило к невозможности запуска всякого говна, вроде хромого.

Anon
()

C++
предсказуемость

/0

anonymous
()
Ответ на: комментарий от geekless

Давайте либо на вопросы будем отвечать, либо не отвечать, нафига друг-друга посылать «подумать», «в гугл»? Так далеко не уедем.

kiverattes
() автор топика
Ответ на: комментарий от Anon

Хромой жрёт как не в себя. Особенно это печально на фоне того, что он кучу раз форкается, и всю эту память тоже надо виртуально дублировать значит. Поэтому Хромой может физически занимать, например 1 гигабайт, но чтобы он работал и не падал, надо еще держать 8 гигов свопа чисто для того, чтобы система знала, что у ней запас по памяти.

geekless
()
Ответ на: комментарий от kiverattes

Я задал вопрос, ответ на который очевиден.

// Эдди, ответь ТСу, почему оверкоммит предпочтителен для сервера. Мне лень писать, я вкусный суп ем. :D

geekless
()

Все твои домыслы про проблемный аллокатор — ерунда. Ищи ошибку в своем коде. Думаю, у тебя либо утечка памяти и, как следствие, заканчивается виртуальное адресное пространство (приложение-то 32-битное?), либо ты допускаешь memory corruption, в результате чего разваливаются внутренние структуры аллокатора.

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

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

Про утечку я наверное косвенно уже написал - при наличии свободных гигабайт происходит проблема выделения 1...2 Мб.

kiverattes
() автор топика
Ответ на: комментарий от kiverattes

Ты нормален вообще? Ты спрашиваешь, почему оверкоммит не бред. Я отвечаю: потому что на сервере это предпочтительно. Какого тебе еще надо?

но речь не идёт о том

Поциэнт, вы уж определитесь. А то на какой вопрос ни ответь, у вас всё не о том.

geekless
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.