что результат её работы в NT-образных платформах одинаковый:
через некоторое время выскакивает мессага "Out of memory"
А мне бы хотелось ловить такие вещи в виде исключений (что бы было в стиле С++)
Есть ли какой нибудь иной способ отлавливать невозможность выделить память
(делать это до системы)? (а то следить за свободной памятью геморойно
и неудобно — и вообще не в стиле С++)
Спасибо за ответы.
Исправлено форматирование. Пожалуйста, пользуйтесь тегами [c] ... [/c], [code] ... [/code] и т.п. для выделения фрагментов кода. -- ПК.
Здравствуйте, Денис Ильин, Вы писали:
ДИ>Добрый день. Есть интересный вопросец.
ДИ>минипрограмка
ДИ>vector <int> nData; ДИ>while(TRUE) ДИ>{ ДИ> try ДИ> { ДИ> nData.push_back(rand()); ДИ> } ДИ> catch(bad_alloc ba) ДИ> { ДИ> printf("bad alloactor!"); ДИ> } ДИ>}
ДИ>что результат её работы в NT-образных платформах одинаковый: ДИ>через некоторое время выскакивает мессага "Out of memory" ДИ>А мне бы хотелось ловить такие вещи в виде исключений (что бы было в стиле С++) ДИ>Есть ли какой нибудь иной способ отлавливать невозможность выделить память ДИ>(делать это до системы)? (а то следить за свободной памятью геморойно ДИ>и неудобно — и вообще не в стиле С++) ДИ>Спасибо за ответы.
дело в том, что винда использует свои собственные не С++ исключение — "структурные исключения", и они не ловятся обычными try/catch
Обычно при сборке проекта можно указать флажок, который приведет к тому, что структурные исключения винды будут транслироваться в С++-исключения, и тогда их можно будет ловить.
Здравствуйте, Денис Ильин, Вы писали:
ДИ>Добрый день. Есть интересный вопросец.
ДИ>минипрограмка
ДИ>vector <int> nData; ДИ>while(TRUE) ДИ>{ ДИ> try ДИ> { ДИ> nData.push_back(rand()); ДИ> } ДИ> catch(bad_alloc ba) ДИ> { ДИ> printf("bad alloactor!"); ДИ> } ДИ>}
ДИ>что результат её работы в NT-образных платформах одинаковый: ДИ>через некоторое время выскакивает мессага "Out of memory" ДИ>Спасибо за ответы.
Боюсь я Вам конкретного ответа не дам, выскажу лишь некоторые соображения.
Соощение появляется из-за того, что система не может осуществить вызов printf()
(Выделить память для размещения параметров в стеке.)
ДИ>А мне бы хотелось ловить такие вещи в виде исключений (что бы было в стиле С++) ДИ>Есть ли какой нибудь иной способ отлавливать невозможность выделить память ДИ>(делать это до системы)? (а то следить за свободной памятью геморойно ДИ>и неудобно — и вообще не в стиле С++)
Я долго медитировал над этим абзацем. Можно попросить Вас сформулировать мысль четче?
Отлавливать невозможость выделить память до системы?
Вмешиваться в работу операционной системы в стиле С++?
Насколько я понял Ваши рассуждения, эта проблема надумана, или перед Вами стояла другая задача, которую Вы свели к данной проблеме.
Копайте в сторону kernel API и исходников OS.
1. Исключение надо ловить по ссылке, избегая его создания — вероятно, именно там-то и возникает пресловутая ошибка.
2. Сделать что-то осмысленное в условиях кончившейся памяти вряд ли удасться. Увы.
Здравствуйте, Vamp, Вы писали:
V>1. Исключение надо ловить по ссылке, избегая его создания — вероятно, именно там-то и возникает пресловутая ошибка. V>2. Сделать что-то осмысленное в условиях кончившейся памяти вряд ли удасться. Увы.
Все это почти правильно... Только а другом (например list<int>) случае... А в приведеном примере что-то я не совсем понимаю почему из недостатка памяти для большого vectora при realoc-e будет следовать недостаток памяти для чего-либо еще. A bad_alloc нужно ловить действительно по ссылке, стандарт гарантирует достаточное кол-во памяти для одного bad_alloc, а не для его копии...
Флажок при сборке проекта? Что бы такие исключения переводились в отлавливаемые catch-ем?
Мне кажется — это будет дорого стоить, потому что мы таким образом можем испортить в другом
месте, где этого совсем бы не хотелось.
Компилера целых два lcc (наиболее желаемый) и VC 6.
В доке к lcc я ничего путного не нашел. Может = плохо искал?
(за форматирование спасибо)
Здравствуйте, Денис Ильин, Вы писали:
ДИ>Флажок при сборке проекта? Что бы такие исключения переводились в отлавливаемые catch-ем? ДИ>Мне кажется — это будет дорого стоить, потому что мы таким образом можем испортить в другом ДИ>месте, где этого совсем бы не хотелось.
Не совсем понятно, что значит испортить? В любом случае exception будет и если ты его раньше не ловил, то и сейчас не поймаешь, если не считать catch(...), но там чаще всего стоит обработчик аля exit...
Денис Ильин wrote:
> что результат её работы в NT-образных платформах одинаковый: > через некоторое время выскакивает мессага "Out of memory" > А мне бы хотелось ловить такие вещи в виде исключений (что бы было в стиле С++) > Есть ли какой нибудь иной способ отлавливать невозможность выделить память > (делать это до системы)? (а то следить за свободной памятью геморойно > и неудобно — и вообще не в стиле С++)
Какой компилятор?
В MS студиях new по-умолчанию не бросает std::bad_alloc, а возвращает 0. Чтобы new бросал std::bad_alloc в семерке, если не ошибаюсь, надо включить хедэр <new>. В шестерке нужно установить new_handler.
так — а вот про ловлю по ссылке я не совсем понял.
(почему нужно ловить по ссылке — я понял, осталось непонятным как написать)
Вот так?
catch(bad_alloc &ba)
{
}
По поводу "напортить" я с вами полностью согласен — это уже из разряда мистики.
Но вопрос остался — про компилеровские настройки.
Я б в МСДН поискал, если б догадался — по каким ключевым словам.
Спасибо. (а у lcc документашка вообще какая то куцая).
Здравствуйте, Денис Ильин, Вы писали:
ДИ>так — а вот про ловлю по ссылке я не совсем понял. ДИ>(почему нужно ловить по ссылке — я понял, осталось непонятным как написать)
ДИ>Вот так? ДИ>
ДИ>catch(bad_alloc &ba)
ДИ>{
ДИ>}
ДИ>
Так. Но в приведеном вначале случае можно и так
catch(bad_alloc&)
{
printf(...);
}
поскольку сам экземпляр исключения не используется...
ДИ>Но вопрос остался — про компилеровские настройки. ДИ>Я б в МСДН поискал, если б догадался — по каким ключевым словам.
у меня new вообще не используется — push_back только. (хотя разве только внутрях push_back-а..)
а push_back всегда возвращает void() (независимо ни от чего).
new_handler — это куды прописать?
По поводу того, что на printf() в стеке места не хватает возражу:
если вместо кучи push_back()-ов сделать один resize() — но большой, то результат будет тот же
хотя на стеке будет памяти — завались.
ага — пока писал — ответ уже появился.
ну да ладно.
А по поводу надуманности проблемы я не согласен.
Почему? Очень просто.
Работает прога. Долго работает. 20 дней. И в ней куча потоков.
Вдруг один из потоков в силу разных причин не смог выделить push_back-ом память.
И все. Прога слетает. А мне бы хотелось, что б остальные потоки остались работать.
Вот это начальная проблема.
push_back всегда возвращает void. Значит вывод очень простой — нужно ловить исключения.
bad_alloc. Но если в самом простейшем случае исключениt не ловится — то ему грош цена.
Хочу поднять эту цену выше, но вот как — этого я пока не знаю.
Возможно (я не уверен!!), VC 6 может кидать в таких случаях SEH-исключение.
Тогда, для того, чтобы его можно отлавливать в стиле С++, можно использовать
_set_se_translator.
Здравствуйте, Денис Ильин, Вы писали:
ДИ>new_handler — это куды прописать?
Есть такая функция setNewHandler (или что-то около того). Этот самый newHandler — это просто функция, которая вызывается, когда мы не можем выделить память. По-моему по-умолчанию она и генерит bad_alloc. Но чтобы все это заработало точно нужно подключить <new.h>
ДИ>По поводу того, что на printf() в стеке места не хватает возражу:
и действительно, причем здесь стек? имеется ввиду, что если printf требует динаического выделения памяти, то....
Есть геморройный выход — самостоятельно написать свой менедлжер памяти, используя низкоуровневый менеджер памяти, используя VirtalAlloc\VirtalFree и тп.
Поверх него свой new\delete.
Может быть сдезь на rsdn уже есть такой?
Правильно работающая программа — просто частный случай Undefined Behavior
Денис Ильин wrote:
> у меня new вообще не используется — push_back только. (хотя разве только внутрях push_back-а..) > а push_back всегда возвращает void() (независимо ни от чего). > > new_handler — это куды прописать?
Ищи в MSDN set_new_handler / _set_new_handler. Вот из своего хэндлера и бросай std::bad_alloc.
Здравствуйте, Денис, Вы писали:
ДИ> что результат её работы в NT-образных платформах одинаковый: ДИ> через некоторое время выскакивает мессага "Out of memory"
Чуть-чуть модифицировал, чтобы быстрее память съедала:
F:\test\out_of_mem>cl -GX test.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
test.cpp
Microsoft (R) Incremental Linker Version 7.10.3077
Copyright (C) Microsoft Corporation. All rights reserved.
/out:test.exe
test.obj
F:\test\out_of_mem>test
bad alloactor!
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: какое исключение ловить?
От:
Аноним
Дата:
15.02.04 12:43
Оценка:
Так у тебя оно вылавливается?
Подробнее пожалуйста — я записываю!
Седьмая студия? Придется её достать. А Винда какая? Тоже интересно.
Я тут поэксперементировал на досуге, и вот что получилось:
Сделал я поиск в MSDN по ключевым словам:
_set_new_handler AND bad_alloc
нашел всего одну тему.
Сделал как там было предложено, а именно:
(решил пока обойтись без STL – для упрощения дела).
Платформа выполнения: WinXP.
В общем: до сообщения “BAD ALLOC” дело не доходит.
Выводимое сообщение = “Out of memory”,
Вся беда в том, что работа будет вестись в сервисе. И ему будет запрещено взаимодействовать с десктопом. А это значит, что это сообщение никто не увидит. А поток будет преостановлен. И единственным способом его завершения станет очень дурацкий метод:TerminateThread. А этого я сильно-сильно не хочу.
В общем – вопрос остается открытым: и ответа я на него пока что не вижу. Можется и вправду 7-ую студию попользовать?
Система — WinXP.
Хотя окошко с предупреждением о том, что виртуальная память заканчивается всёже появилось, но только 1 раз из 3-х запусков.
Можно попробовать подавить его средствами WinAPI — вроде есть фуцнкция, хотя нехватка памяти — это дело всей системы, а не только твоей проги, и месагу может вовсе какй системный процесс вываливать.
Я бы лучше попытался несколько ограничить аппетиты проги, или как-то следить за этим делом. ;-в
В общем — рассказываю в чём было дело.
Наверняка кому нибудь понадобится.
Во первых, все эти bad_alloc-и нужно было вылавливать после
следующей операции:
#include <new.h>
#include <new>
using namespace std;
int _cdecl my_new_handler(size_t)
{
throw bad_alloc();
return 0;
}
_PNH _old_new_handler;
_old_new_handler = _set_new_handler(my_new_handler);
..//тут вся ботва с try catch - в этом случае bad_alloc будет генерироватьсяtry
{
}
catch(bad_alloc &ba)//стандарт не гарантирует появления копии bad_alloc-а
//поэтому ловить его нужно по ссылке
{
//сделать что нибудь
}
_set_new_handler(_old_new_handler);
Вот. Это во первых.
А во вторых — мессаго Out of memory вываливалась при использовании MFC(!)
При чем в любом случае.
Кстати, в этом случае такая перегрузка не поможет.
Вывод: используете MFC — ловите только MFC-шные исключения
Другие скорее всего не придут. (даже bad_alloc!)
(вечно у дяди Билли со стандартами напряженка).
Исправлено форматирование. Пожалуйста, пользуйтесь тегами [c] ... [/c], [code] ... [/code] и т.п. для выделения фрагментов кода. -- ПК.
Re: какое исключение ловить?
От:
Аноним
Дата:
16.02.04 10:22
Оценка:
Здравствуйте, Денис Ильин, Вы писали:
ДИ>Добрый день. Есть интересный вопросец.
ДИ>минипрограмка ДИ>
ДИ>что результат её работы в NT-образных платформах одинаковый: ДИ>через некоторое время выскакивает мессага "Out of memory" ДИ>А мне бы хотелось ловить такие вещи в виде исключений (что бы было в стиле С++) ДИ>Есть ли какой нибудь иной способ отлавливать невозможность выделить память ДИ>(делать это до системы)? (а то следить за свободной памятью геморойно ДИ>и неудобно — и вообще не в стиле С++) ДИ>Спасибо за ответы.
Скорее всего у Вас VC6.0 В них оператор new не выкидывает исключение, а просто возвращает нулевой указатель.
В общем так:
проверил на всех компилерах: 5..7. В общем — отделив мухи от котлет я
понял — что это именно MFC. И ловить нужно было MFC-щные исключения.
Но вопрос про _set_new_handler остался — достаточно ли его в многопоточной
проге сделать один раз (Multithreaded CRTL как это воспринимает —
сразу на все потоки, или только на текущий)?