| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Visual C++/MFC/WTL > wincore.cpp |
| Автор: mrgloom 9.9.2011, 13:10 | ||
| в режиме дебага когда идет запись в вектор на функции SomeFuncPushTovec(); вылетает на
по стэку вызовов понять ничего не удалось. предполагаю, что что то связанное с ограничением на память (в е CMemoryException). почему это происходит? |
| Автор: Earnest 9.9.2011, 17:13 |
| Стек вызовов в момент отлова исключения рассматривать бесполезно. Нужно ловить исключение в момент генерации. Во первых, нужно понять какой тип исключения. Это можно увидеть (в дебаге) в Output-окне. Там должно быть написано что-то вроде First chance exception at... Далее нужно в окне Debug-Exceptions включить перехват нужных типов исключений; можно сразу группу, а не поштучно. Если тип исключения понять не получается, попробуй C++ exceptions и Run-time (не помню. точно как называются - там где Access violation и т.д.) Вот в момент генерации исключения смотри стек. Иногда бывает, что ты ловишь не первичное исключение, а "переизлученное". Тогда нужно еще поработать с окном перехвата исключений... и внимательно смотреть Output (найти самое первое исключение) |
| Автор: mrgloom 12.9.2011, 11:47 |
| во время дебага нажал Ctrl + Alt +E и поставил галочку напротив С++ Exeptions->CExeption ну и дебагер остановился на том же месте CATCH_ALL(e) тип исключения CMemoryExeption в логе дебаг окна Microsoft C++ exception: CMemoryException at memory location я так и не понял как посмотреть из какого куска кода оно пришло. |
| Автор: Earnest 12.9.2011, 13:01 |
| Возможно, что-то сделано неправильно. Но бывает, и что не срабатывает. Тогда попробуй отловить момент создания исключения CMemoryException - поставь точку прерывания в MFC-коде. |
| Автор: mrgloom 12.9.2011, 16:26 |
| надо было перед дебагом. вообщем. First-chance exception CMemoryException at memory location bgheap.c на строчке /* do the allocation */ pvBlk = _heap_alloc_dbg_impl(nSize, nBlockUse, szFileName, nLine, errno_tmp); посмотрел по стеку похоже просто не может выделить память в вектор (машина имеет 2гб. оперативной памяти заполняется полностью) хотя пробовал запускать откомпилированный экзешник на машине с 4Гб всю память не занимает, а вываливается примерно на 2Гб. |
| Автор: Earnest 12.9.2011, 16:35 |
Похоже??? Если ты реально ждал, что тебе 2 гб в хипе выделят, тебе срочно нужен ликбез - надо книжку какую-никакую прочесть, про виндоус, про память и т.д., Рихтера, например. |
| Автор: mrgloom 13.9.2011, 09:55 |
| ну я так подозреваю что 2гб это предел для приложения в х32 системе? (хотя вроде тяжелые приложения как то расширяют это дело до 3Гб). попробую под х64. и еще как то можно оценивать полный объем памяти, который использует программа, чтобы она не падала на х32? Upd: на х64 та же история (2GB per process) или я чего то делаю не то. хотя на х64 всего 2Гб памяти так что может быть и в этом проблема. |
| Автор: mrgloom 13.9.2011, 12:03 |
| пробовал этот метод скомпилировать с флагом /LARGEADDRESSAWARE http://msdn.microsoft.com/en-us/library/wz223b1z эффект тот же, хотя возможно из-за того, что х64 имеет 2Гб, но по идее есть еще и файл подкачки. |
| Автор: Earnest 13.9.2011, 12:41 |
| На 32-битной платформе процессу выделяется 4 гб виртуального адресного пространства. Больше не позволяет адресация. В это же адресное пространство отображаются все необходимые системные библиотеки, а также сам процесс. Сколько памяти есть физически в системе - не важно, это будет влиять только на скорость (разве что на диске не хватит места под своп или своп вообще отключен). Под хип остается то, что не занято стеком и прочими запросами на память. Причем хип может фрагментироваться. Так что рассчитывать на большой кусок не стоит. Под 64-битной платформой памяти процессу должно выделяться по идее больше. Почему у тебя не получилось, не знаю. Разве что ты не компилировал под 64, а просто запустил 32-битное приложение. |
| Автор: mrgloom 13.9.2011, 17:34 |
| нет я скомпилировал под х64(статическая линковка на выходе только 1 экзешник, флаг /LARGEADDRESSAWARE проставил насильно) (на системе х32 специально проверил экзешник не запустился) перенес на систему х64 и запустил там(только там 2Гб памяти) и начал смотреть что там происходит через vmmap примерно когда heap занимал 1.8Гб , а полный размер ~2Гб все начало свопиться и начались дикие тормоза, а потом все равно приложение вроде бы упало. может нельзя выделять больше 2Гб непрерывной памяти? или на это нет ограничений? |
| Автор: mrgloom 14.9.2011, 09:19 | ||
| запустил на машине х64 с 4 гб, программа отъела 4Гб и сообщила, что ей не хватает памяти. вообщем все работает, но почему то файл подкачки она кушать не хочет. причем программа не падает, но и память не сбрасывает. т.е. она кушает много памяти на ф-ии add_many_items_to_vector() потом вылетает эксепшн на память и как дальше она себя ведёт\должна вести не очень понятно. Добавлено через 4 минуты и 15 секунд может возможно контролировать как то поведение программы на таких участках? или как то все время проверять с какой то периодичностью. что то типа
|
| Автор: Earnest 14.9.2011, 09:42 |
| Может, проще не жрать столько памяти? Я за свою довольно долгую карьеру ни разу с таким проблемами не сталкивалась... Нельзя же программировать на абстрактной машине Тьюринга. |
| Автор: mrgloom 14.9.2011, 11:02 |
| заранее рассчитывалось, что приложение может есть много памяти. аппетиты конечно сократятся, но хотелось бы уметь и обрабатывать такие ситуации нехватки памяти. |
| Автор: mrgloom 14.9.2011, 13:44 |
| т.е. даже по сути вопрос сводится к тому как в программе должно обрабатываться при нехватки памяти скажем такое while(1) { vec.push_back(item); } почитал тут http://users.msu.dubna.ru/~nefedov/c++course/p2-3.html но там про new[],но я то работаю со стандартным вектором. |
| Автор: Earnest 14.9.2011, 15:17 |
| У тебя же генерируется CMemoryException? Вот его и лови. Хотя странно, если std::vector, там другой тип исключения; точно не помню, тоже про память. Короче, выясни тип исключения и лови, в чем проблема? Кстати, имей в виду. Вектор растет не по одному элементу а кусками. Причем, алгоритм определения размера прироста обычно довольно простой - типа удвоения текущего размера. Т.е. если тебе не хватит места всего под один элемент, вектор попытается раздуться вдвое. И может лопнуть. Далее, перевыделение памяти происходит так: выделяем новый кусок, копируем туда старые значения, освобождаем старый. В результате - память фрагментируется! Т.е. возможен случай, когда память вроде есть, на 1000 мелких кусочков. Но вот на один большой (равный в сумме 1000 мелких) - фиг вам. Короче, при больших аппетитах полагается сразу определиться с примерно нужным размером и заказать его сразу + небольшой запас, возможно. Нельзя с большим вектором работать точно также как с маленьким. |
| Автор: mrgloom 4.10.2011, 09:20 |
| если есть vector<vector<point>> и я точно не знаю размер внутренних векторов и внешнего вектора, но например хочу под это дело выделить кусок памяти 2Гб, как это можно сделать? |
| Автор: Earnest 4.10.2011, 10:39 |
| Никак, разве что свой аллокатор писать. Либо дизайн пересмотри. Например, можно сделать так: выделить большой пул для всех точек в виде vector<point>, а отдельную линию хранить как <начало-конец>. Либо как-то еще упаковать, и прописать извлечение в виде объекта. Это требует довольно много кода, но при работе с большими массивами данных обойтись стандартными контейнерами не получится. Например, у меня в программе векторные данные хранятся в виртуальной памяти (а не в хипе), в виде упакованных блоков, без всяких указателей. Для каждого слоя есть 2 параллельных пула: массив тэгов фиксированного размера (тэг - это структура, где записан тип объекта, экстент, размер, позиция во втором пуле и некоторые доп. данные). Второй пул содержит блоки разных размеров, где хранятся собственно данные (массив координат и т.д.). На оба пула сверху навернута поддержка списка свободных блоков. Все это закрыто в наборе классов, наружу торчат только ручки типа "Разместить объект", "Удалить", "Изменить". Объект извлекается в виде пары указателей (на тэг и данные), сверху навернуты объектные обертки. Причем их два типа (2 набора): "легкие" обертки, только для чтения, зато быстро создаваемые (например, прорисовка или поиск) и полновесные классы, для редактирования/создания. Смысл примерно такой: упакованные данные занимают намного меньше места, меньше страдают от фрагментации, легко сериализуются (всем куском); для чтения (рисования) достаточно inline-оберток, которые преобразуют указатели к нужному типу и ничего не стоят. А полноценный объектный доступ нужен только при редактировании отдельных объектов. Тогда точки копируются в вектора (для полилиний), модифицируются, а потом снова упаковываются. |
| Автор: mrgloom 4.10.2011, 14:39 | ||
| у меня проблема несколько в другом у меня данные хранятся не в готовом для вывода виде, а в виде типа 1.есть описание объекта.(какая то фигура, например квадрат) 2.есть действия над объектом(переместить в точку, повернуть и т.д.) т.е. весь файл например состоит из N таких фигур, но с разными действиями над ними, возможны вложенности одних фигур в другие. "развернуть" все эти "заготовки" в реальные примитивы я не могу т.к. займет много памяти, приходится выцеплять частями, только те которые нужно. в памяти я храню только описание объектов+ "куда их поставить". я заранее простчитываю ограничивающие прямоугольники объектов и потом в цикле(когда надо отрисовать) накладываю на них преобразования(переместить, повернуть..) и проверяю 1. Если ограничивающий прямоугольник пересекается или попадает в текущий видимый в программе прямоугольник. 2. если размер прямоугольника достаточно большой(чтобы не выводить маленькие). вообщем проблема в том, что при каждой отрисовке гуляет размер вектора, который содержит данные для отрисовки, и его размер может меняться, в теории я на каждой итерации могу оценить его размер, но это скажется по процессору. скорее всего придется выводить "порциями", т.е. дошли до лимита скажем в 10к элементов- вывели, потом опять ищем. но как этот лимит правильно определить хз, т.е. если вообще по 1 примитиву выводить лишней памяти не надо, но будет медленно. вот код отрисовки, приходится еще выделять доп. память под временное хранилище. vec это vector<vector<vector<point>>> , он содержит vector<vector<point>> т.е. список примитивов, которе приходят из разных тредов.
|