LINUX.ORG.RU

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


0

1

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

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

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

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

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

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

Ответ на: комментарий от stevejobs

ну так сжатие/дедупликация страниц ведь.

ТСу: запускай valgrind и тереби мозг

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

Да, в общем случае это корректней. И я даже так делаю иногда.

Ручной преинит больших блоков корректнее как раз не в общем случае, а в частном - работа ответственного ПО на фоне истощения ОЗУ. Чтобы застолбить себе непрерывные диапазоны необходимых страниц на старте, или не запуститься вовсе. Мелочь естественно, можно не преиничивать, да и не всегда есть возможность это сделать. А «посоны в глибц» вообще не могут и не должны делать никаких предположений о характере эксплуатации ОЗУ прикладными программами.

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

Чтобы застолбить себе непрерывные диапазоны необходимых страниц на старте

На старте - ключевой момент.

преинит больших блоков корректнее как раз не в общем случае, а в частном

Я говорил о корректности в плане последующей работы (если вдруг) не с мусором, а хотя бы с нулями.

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

На старте - ключевой момент.

Ключевейший. Если программа построена так, что ей на ходу нужны массивные переаллокации, то ей уже ничего не поможет это не тот юзкейс.

Я говорил о корректности в плане последующей работы (если вдруг) не с мусором, а хотя бы с нулями.

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

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

а можно на старте отожрать себе гиг непрерывной памяти, а потом сделать на нем свой собственный new с блекджеком?)

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

Конечно, есть placement new специально для этого.

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

Если непрерывной виртуальной, то это паттерн pool (типа свой аллокатор)

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

Для уведоиления юзеров достаточно использовать тег [user], например так:
[user]kiverattes[/user]

Результат: kiverattes

Ну как, уведомление пришло? :)

Lorcode FAQ

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

[offtopic]

unsigned long int size;
printf("Requested %i MB...", size);

Ай-ай-ай так делать.

mem = malloc(size*bsize);

Приводить тип надо, с -pedantic не соберётся же.
[/offtopic]

Попробовал запустить это с

MemTotal: 4032092 kB 
SwapTotal: 7999956 kB
из них 1.3G заняты. А также:
$ find /proc/ -name '*overcommit*' -exec echo {} \; -exec cat {} \; 2>/dev/null
/proc/sys/vm/nr_overcommit_hugepages
0
/proc/sys/vm/overcommit_memory
0
/proc/sys/vm/overcommit_ratio
50

$ uname -a
Linux User-PC 3.8.0-30-generic #44-Ubuntu SMP Thu Aug 22 20:52:24 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

Ушло в лютый свап на «Requested 3650 MB... OK» мокго терпения хватило на «Requested 5900 MB... OK»

Посему сделал swapoff -a и запустил снова:

...
Requested 2400 MB...Failed!

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

Каюсь, дальше не читал. Этот пост мне взорвал мозг, поэтому у меня временно настало 404, и я не мог продолжать чтение топика.

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

malloc возвращает адрес в виртуальном адресном пространстве процесса, полученный либо увеличением адресного пространства процесса(sbrk, сюда входит уже ранее выделанная и освобождённая память), либо мапингом(mmap). Полученному виртуальному адресу постранично(в зависимости от использования) выделяется физическая память, и она не может вдруг внезапно на пол пути закончиться, т.к. ядро контролирует количество доступной физической памяти для всех процессов. Так что, маллок либо даёт то количество памяти что попросили(не меньше), либо вовсе не даёт.

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

Блин, ну как же! Имеем, скажем, высоконагруженный сервер. С памятью вечно сложности. Кто-нибудь начинает отгрызать себе пару сотен мегабайт, постепенно заполняя страницы. Но тем временем еще кто-то освобождает помаленьку память. В общем, смысл есть.

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

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

В данном случае профит получаем от свапа, а не от возможности прыгнуть выше головы. Или я не догнал?

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

можно попробовать написать нормальный garbage collector

но по-простому всё равно нормальный не получится

нужно будет наращивать и наращивать мясо

в результате получится Mono

а можно сразу взять Mono

хотя, емнип, Mono как раз написан на чистом Си... :-(

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

Куда-то тебя не в ту сторону завернуло.

Для любых систем, которые должны малой кровью переживать нехватку ресурсов, быдлокодеров и прочие стихийные бедствия (т.е. для ВСЕХ систем), самое главное — правильная изоляция объектов.

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

Убийство процесса мгновенно освобождает ресурсы и избавляет нас от разгребания последствий того, что он мог бы натворить.

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

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

Ну насчет мгновенно освобождает ресурсы вопрос спорный, не освобождал как-то ресурсы в программе, они в иксах висели, даже после убийства программы.

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

И нет, ты даже близко не понимаешь как работает менеджер памяти, начиная от его связи (на самом деле, её отсутствия) с ОС

пруф будет? про «отсутствие связи»? Т.е. ты хочешь сказать, что в Linux 3.x и в MSVC один и тот же код делает ::new?

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

Доктор, конечно же не решит! Но все равно malloc приятней. А в плюсах я вообще не соображаю. Писал тут пару недель назад обертку над плюсовой библиотечкой для работы с ПЗС-камерой, затрахался! Вот же людям делать нечего! Ладно бы там использовались всякие наследования и т.п. фишки плюсов. Дык, обычный код в стиле сей, но на плюсах. Уроды, блин!

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

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

ВНЕЗАПНО: malloc вообще память НЕ выделяет. Т.е. если ты написал malloc(Over9000Mb) у тебя «выделится» Over9000Mb как ты и просил. Ошибки НЕ будет. С т.з. аллокатора у тебя ровно 2**64-1 байта памяти. Потому Over9000Mb у тебя есть _всегда_, даже если в системе всего 512Мб.

Выделяется некая «виртуальная» память (VIRT), которой нет. Некоторые быдлокодеры используют memset(), но это плохая идея, если система выполняет больше одной задачи.

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

Доктор, конечно же не решит! Но все равно malloc приятней. А в плюсах я вообще не соображаю.

ну в том-то и дело. А мощь плюсов как раз и заключается в том, что тебе не нужно думать о разных мелочах, вроде освобождения памяти. Память освобождается «сама», деструктором. Ты не сможешь «забыть» освободить память, потому-что это не нужно. А вот в C (без плюсов) ты _можешь_ сделать утечку. Естественно, это работает только при грамотном проектировании класса, который выделяет память(нужно использовать виртуальные деструкторы, нужно использовать smartr pointer, нужно внимательно перезагружать и определять operator=() и конструктор копий, есть и другие широко известные правила). Если всё делается по правилам, то код пишется также быстро и просто как на этих ваших питонах/жабах, и при этом работает также быстро как на сишечке.

Проблема в том, что многие быдлокодеры правил не знают/не соблюдают, и потом обижаются. Да, это C++, тут нет жёстких правил, тут можно всё писать в одну строку, даже откровенный быдлокод. Но разве эта вина плюсов? По моему продуманному мнению, это проблема исключительно автора быдлокода.

Дык, обычный код в стиле сей, но на плюсах. Уроды, блин!

профит плюса — быстрый код. Который и пишется быстро, и работает быстро. За счёт того, что много кода можно юзать повторно. Точно также, как и в php. Ты же не делаешь списки/стеки/строки на php? Нет, они там уже есть. А вот в C++ их «нет», но ты можешь использовать либо чужой код (например STL), либо свой. Даже new можно перезагружать как глобально, так и в пределах класса. Потому стона о том, что «в C++/C плохой new/malloc» == лютое 4.2. Никто не запрещает юзать свой Самый Лучший. Правда в сишечке это требует сильной переделки кода, на вот в C++ всё просто и быстро.

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

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

говно == твой код, который memset'ит всю свою память, даже она не нужна.

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

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

вот а я вижу, что в твоей голове взрывоопасная каша, и пока ты не разберёшься, код тебе лучше НЕ писать. Только для однозадачных контроллеров с 64К памяти, по типу Z80. :)

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

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

твоему приложению будет отправлен SIGKILL, которое оно и не увидит, ибо будет убито. И поделом, ибо быдлокод.

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

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

4.2 Chrome у меня работает на 1.5Гб + 1Гб свопа. Течёт, да, причём течёт через иксы (т.е. иксы пухнут, и жрут всё больше и больше. Перезагрузка хромого не помогает. Перезагрузка иксов помогает). Но часов 10 можно работать. А вот ФФ отлично работает даже с таким количеством памяти.

Т.е. твой пост — очередное произведение диванного теоретика. (очевидно, десктопного линукса у тебя под рукой нету)

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

Я отвечаю: потому что на сервере это предпочтительно

на десктопе — тоже. Именно за счёт оверкоммита УМВР.

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

Мы говорили про выключенный оверкоммит, дибилушка.

кто из нас «дебилушка»? Сделать из нормальной ОС маздай, а потом обсуждать, почему всё так хреново?

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

А другой памяти с точки зрения пользователя ядра и нет, кроме виртуальной. Поэтому некорректно говорить, что malloc память не выделяет. Память есть единственного типа - виртуальная. И её выделяет malloc().

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

а можно на старте отожрать себе гиг непрерывной памяти, а потом сделать на нем свой собственный new с блекджеком?)

можно. Если не боишься, что тебе яйца оторвут. Ага, «благодарные» пользователи.

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

Это не относится к сабжу, но по теме Chrome - странно: на работе и дома использую какие-то версии Chrome (из последних) и аптайм xorg (1.11.3) - на моих системах - месяцы. Сейчас на доступной мне системе аптайм иксов - 19 дней, активно юзается много Chrome, иксы сожрали 151800 (VIRT) 52096 (RES).

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

А другой памяти с точки зрения пользователя ядра и нет, кроме виртуальной. Поэтому некорректно говорить, что malloc память не выделяет.

верно. Физической памяти не выделяет, а выделяет только виртуальную. Но как она может «кончится»? Правильный ответ: никак. И это не баг, а фича, система выделяет память ровно столько, сколько нужно. Т.е. new/malloc вообще ничего не решает в плане выделения _физической_ памяти, она выделяется во время выполнения программы. А если она не выделяется, то это — авария. Причём авария не конкретно приложения, а ВСЕЙ системы.

Память есть единственного типа - виртуальная.

нет. Виртуальная память становится резидентной в момент обращения. Потом она снова может стать виртуальной, если её вытеснить в своп.

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

Стандартная библиотека C/С++ примерно так себя и ведёт - у системы она просит память оптом, а потом через оператор new() или malloc() нам её нарубает на куски и хранит информацию о размерах этих кусков. Как-то раз в одном проекте нам нужно было создавать очень много мелких объектов, но удалять их по отдельности было не нужно. Был сделан аллокатор, который просит у системы память мегабайтами, а пользователю отдаёт кусочки, не запоминая о них никакой метаинформации (размер), за счёт чего кусочки лежали вплотную, их невозможно было освободить отдельно, но неплохо экономилась память. Потом мы просто возвращали системе вагон памяти оптом, не занимаясь удалением в ней отдельных объектов.

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

Это не относится к сабжу, но по теме Chrome - странно: на работе и дома использую какие-то версии Chrome (из последних) и аптайм xorg (1.11.3) - на моих системах - месяцы.

ну возможны варианты. Может кривой быдлофлеш криво работает, может ещё что-то. Возможно у меня просто сайты такие кривые.

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

Но как она может «кончится»?

Виртуальная память может кончиться, если значение системной переменной, в которой лежит её свободный виртуальный объём дошло до нуля. Ваш Кэп ) Например в моей системе с 8 гигами ОЗУ виртуальной памяти - 12 гигов. Выделю 12 гигов и она кончится.

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

Это системные тонкости, зависящие от ОС, а с точки зрения пользователя функции malloc()/new() и т.п. она никакой не «становится», а всегда является просто памятью.

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

Когда я писал под xlib напрямую, я помню был эпизод, когда я выделял (просил у иксов) «пиксельные буферы». Они используются всегда, когда надо показать картинку. Я помню, что их можно было забыть освободить, отчего иксы пухли и дохли.

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

Можно, но нам надо было без рестарта раз в сутки выгрузить всё мясо и загрузить снова (с диска).

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

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

kiverattes ★☆
() автор топика
Последнее исправление: kiverattes (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.