Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Прога на С++ Builder 5.0 кушает память. Помогите.


Автор: VisualCraft 3.2.2004, 03:57
//Подготовка
Query1->SQL->Text="INSERT INTO table1(Field1,Field2) VALUES ("+v1+","+v2+")";

//Проверено, именно этот кусок кода регулярно кушает память примерно по 100-200 байт
try{Query1->ExecSQL();}
catch ( ... ){ //Попытка дублирования первичного ключа
try{
if(Query1->Active) Query1->Close();
Query1->SQL->Text="SELECT * FROM table1 WHERE Field1="+v1;
Query1->Open();
if(Query1->IsEmpty()){ //Обновить запись свежими данными
Query1->SQL->Text="UPDATE table1 SET Field2="+v2+" WHERE Field1="+v1;
try{Query1->ExecSQL();}
catch ( ... ){/*это никогда не случается*/}
}
}
catch ( ... ){/*это никогда не случается*/}
}

VCL грязно работает?
В чем тут дело и как победить?

Автор: Дрон 4.2.2004, 12:49
Решил проверить твой код, хотя и не очень шарю в БД. Наткнулся на интересную вещь.

1. Заключил всё в цикл и проверил (память считал Диспетчером задач):
Итак за 5000 итераций сожрал 20Мб памяти.
Потом я создал ему файл table1.dbf и на 5000 итераций ушло 5Мб памяти.
Дальше решил проверить в чём дело.
Закомментировал все обращения к Query -- всё в порядке, сколько было при запуске столько и остаётся.

2. А дальше возникла идея.
Написал я в первом блоке try, код вызывающий деление на 0 -- а это тоже исключение.
Ну и запустил (при этом опять же БЕЗ обращений к Query).
На 50000 итераций ушло около 3Мб памяти (т.е. при запуске было ~5Мб, после прогона цикла стало ~8Мб).

3. Потом ещё проверил простым throw 0.
А вот он, как оказалось, память не кушает.

4. Делаем выводы: Память жрут исключения. Но не по своей природе, а из-за какой-то хитрой фичи товарищей из Borland. smile.gif
Почему? Не знаю.

P.S.
Может быть, этот Диспетчер не правильно память меряет.

P.P.S.
По своей природе они (исключения) тормозят программу. Даже throw 0 замедлял прогон цикла где-то в 10 раз... Но это уже отдельный разговор.

Автор: VisualCraft 4.2.2004, 17:26
У меня тоже это в цикле, наблюдаю и сердце кровью обливаецца.
Придется алгоритм изменить для минимизации исключений.
Но проблема все равно остается, т.к. прога предназначена для круглосуточной работы....
С таким багом это невозможно.

Автор: VisualCraft 4.2.2004, 17:36
Кстати, там опечатка,
вот так должно быть if(!Query1->IsEmpty()) //Не пуст,
но это не принципиально, просто исключений намного больше.
У меня то правильно написано.

Автор: VisualCraft 4.2.2004, 17:42
Может в блоке catch(){}
нужно вызывать какую то неизвестную функцию "уборки мусора"?
Что-то ничего такого не нахожу.

Автор: Vyacheslav 4.2.2004, 17:57
Первое. Если утечки смотрели диспетчере - это еще может быть и не утечки. Если у тебя есть форма в приложении, после цикла минимизируй ее, а потом опять восстанови и посмотри сколько отсталось памяти за программой.

Второе. Убери все строковый константы к в AnsiString константы. Использование неименованных строковых констант - плохой стиль. Кроме того при присвоении этих строковых констант свойствам(на самом то деле мы знаем, что вызываются функции) создаются временные AnsiString переменные, а вот их особождение при генерации исключения совсем не гарантируется
Т.е. надо сделать следующее

const AnsiString cStr1 = "="INSERT INTO table1(Field1,Field2) VALUES (";
...
и далее по коду использовать их

Автор: Дрон 4.2.2004, 23:56
Цитата
после цикла минимизируй ее, а потом опять восстанови
Да, действительно, на вкладке Процессы при этом уменьшается кол-во используемой памяти. И вообще на той вкладке как-то странно считается используемая память...

А вот на вкладке Быстродействие -- всё равно продолжает уверенно увеличиваться по мере работы цикла с VCL исключением.
Забавно было бы если бы винда своповаться начала, да только у меня памяти 512 -- ждать слишком долго smile.gif

Если кто знает -- разъясните, пожалуйста. Может я в чём-то ошибаюсь? А то ведь странно всё это получается, очень даже странно smile.gif

Автор: Vyacheslav 5.2.2004, 10:14
Есть ли у тебя утечка реальная утечка памяти, можно выявить только одним способом - с помощью дебагера. Для С++ Builder проще всего использовать CodeGuard. Если он покажет, то утечка дейсствительно есть. Если не покажет, то скорее всего это особенность работы Windows c памятью.
Насчет использования неименнованных констант, приводящих к созданию скрытых переменных объектов. Вот такой пример вызывает утечку памяти
Код

сlass MyClass
{
 public:
   MyClass(String );
   ~MyClass(void);
 private:
   String FileName;
   void ErrFunc(void);
};
//---------------------------------------------------------------------------
MyClass::MyClass(String aFileName) :FileName(aFileName)
{
   throw 1;
}
//---------------------------------------------------------------------------
MyClass::~MyClass(void)
{
 ShowMessage("destructor");
}
//---------------------------------------------------------------------------

void __fastcall TForm2::Button1Click(TObject *Sender)
{
   for(;;)
 try
 {
  new MyClass("hghghghghghghghghghghghghghghghghghghghgh" );
 }
 catch(...){}
}


А вот небольшое изменение, которое утечку ликвидирует
Код

void __fastcall TForm2::Button1Click(TObject *Sender)
{
 AnsiString Test = "hghghghghghghghghghghghghghghghghghghghgh";
 for(;;)
 try
 {
  new MyClass(Test );
 }
 catch(...){}
}


Автор: Дрон 5.2.2004, 12:54
Утечка есть!
CodeGuard молчит. Но зато если вырубить виртуальную память, поназапускать кучу программ так, чтобы свободными осталось мегабайт 20, запустить цикл с исключением и чуть-чуть подождать, то начнутся очень забавные вещи smile.gif

А что касается решения, то я, кажется, кое-что нашёл:
Код
try{
...
}
catch(Exception &e){
...
e.Free(); // вот оно!
}

И тогда всё становится very good.
Правда, в help написано, что не надо вызывать метод Free, а надо использовать оператор delete, но как же я его для ссылки-то использую? smile.gif
И вообще, удивляет то, что нигде не сказано, что после обработки исключения память нужно освобождать вручную.

Автор: VisualCraft 5.2.2004, 13:58
Спасибо Дрон!
А я нашел аналогичный пример для VC++
Там как раз это сказано слегка. Век живи век учись.
catch(СException *e){e->Delete();}


Автор: VisualCraft 5.2.2004, 14:02
Шутка юмора
Кстати, це не кажется Вам странным шо в выжуал Сы
усе на Цэ начинаецца )))))))))))))))))))
Цэ эксэпн ! Я и без них бачу шо цэ эксэпшн...

Автор: Puksant 16.8.2004, 13:40
У меня похожая беда, но код

try{
...
}
catch(Exception &e){
...
e.Free(); // вот тут
}
выдает нарушение доступа к памяти. Если можно пример с реальным кодом.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)