Знаю, что переменные можно очищать с помощью dispose(); Но переменных в памяти очень много, можно ли каким-либо образом очистить всю память, занимаемую программой?
Перед тем, как очищать память, надо знать, как эта память выделяется. Если выделял через GetMem - то освобождать надо через FreeMem, если выделял конструктором какого-то класса - то вызывай его деструктор, и т.д. При правильно структурированной программе таких ошибок возникать не должно. Я не знаю, как там у тебя память выделяется, поэтому советов, "как очищать" давать не буду. Хочешь - показывай программу, посмотрим, что можно поправить...
Цитата
Почему-то график пустует, хотя ко времени вызова StrinGrid уже заполняется
Почему=то мне кажется, что даже если график и заполнится - там может быть полно "мусора". Лучше все-таки сделать так:
procedure Tf_main.Grafiki; var i:integer; a1,a2:real; begin Series1.Clear; for i:=1 to 5 do if (GridResult.Cells[1, i]<>'') and (GridRoom.Cells[5, i]<>'') then begin a1:=StrToFloat(GridRoom.Cells[1, i]); a2:=StrToFloat(GridRoom.Cells[5, i]); Series1.AddXY(a1, a2, '', clRed); // Добавлять в грид только тогда, когда A1 и A2 изменяются end; // Edit16.Text:=FloatToStr(a1); end;
Цитата
Это может быть из-за того, что числа в колонках большие: 5 знаков до запятой и 5 после?
Вряд ли. Добавляться к графику точки все равно должны.
> если выделял конструктором какого-то класса - то вызывай его деструктор
Деструктор, который надо вызывать руками... Ни в одном другом языке такого бреда нету - везде либо ГЦ либо РАИИ, либо вообще понятие деструктора отсутствует. Позор ботланда, вечный костыль дельфи...
Ну, что есть - то есть... По мне - так лучше я руками соберу там, где это надо, чем GC будет решать за меня, когда и где память освобождать.
Кстати, что в современном Дельфи (2009 и выше) есть возможность написать аналоги С++-ных auto_ptr, тогда будет чуть проще с освобождением памяти... Но это только на новых версиях...
> По мне - так лучше я руками соберу там, где это надо, чем GC будет решать за меня, когда и где память освобождать.
А ещё лучше нормальный RAII.
> Кстати, что в современном Дельфи (2009 и выше) есть возможность написать аналоги С++-ных auto_ptr, тогда будет чуть проще с освобождением памяти... Но это только на новых версиях...
Видел я эти аналоги - только не auto_ptr, а shared_ptr. Я и в Д7 умею делать приведение к интерфейсу. Только это, во-первых, обязательно через счётчик ссылок работает (а если мне нужно другое поведение?), а во-вторых, это дико тормозить будет. Проверяли - делали большой массив, загоняли в него 1000 раз по 10 ссылок на один объект, сортировали. В Д7 большую часть времени занимала работа интерфейсов, С++-ники ржали долго. Адский же код с контролируемыми объектами показал себя на нормальном уровне, правда я не знаю, вызовы деструкторов там виртуальные или статические, надеюсь, что компилятор догадался.
Извините, код громоздкий, но всё же выложу, не понимаю почему не строятся графики, помогите, пожалуйста, может и про память что-то дельное сказать можно?
Код удален
procedure Tf_main.Button1Click(Sender: TObject); - вызывает функции расчета величин Вывод в GridResult осуществляет процедура procedure TzoneMath.ShowOnTable(grid:TStringGrid; room:integer); После неё я использую процедуру Grafiki Т.о. по моей мысли графики должны строится, но почему-то из таблицы считываются нулевые значения...
Добавлено через 3 мин. Извините еще раз, а как сделать, чтобы в сообщении код показывался с полосой прокрутки?
Ты б лучше запаковал весь проект и выложил сюда, а то что ж получается, надо еще восстановить форму, чтоб запустить проект? Только EXE-шник удали, не надо его присоединять, меньше будет архив по размеру.
Цитата
а как сделать, чтобы в сообщении код показывался с полосой прокрутки?
На этом форуме нет такого функционала. Еще раз: если код длинный - лучше его архивировать и прикладывать к посту...
А в программе у тебя полный бардак, я попробую посмотреть, что можно сделать... У меня она вообще не запустилась - выбросила сообщение "Недостаточно памяти для осуществления операции". Посмотрю, почему.
У меня такое сообщение вылетает, когда я раза 3-4 подряд вызываю функцию расчет, я не очищаю память вообще нигде, что больше всего ест памяти? Изображения, что строятся и где-то хранятся или множественные расчеты величин с 5 знаками после запятой? Можно в принципе сократить до 2-х знаков...
Так... Во-первых, Buffer типа TImage, можно убрать, он не используется. Только жрет место. И много жрет, ты резервируешь для него достаточно большой размер памяти (увеличением Width и Height). Итого: процедура Tf_main.BitBtn1Click
Спасибо большое, понял в чем ошибка с графиками, 2 дня с ними мучался и не заметил, что название StringGrida во втором условии перепутал, поправил, только вот теперь он ругается: EConvertError "" is not a valid floating point value. А по поводу памяти можно еще вопросик: bufferы можно убрать, а изображение при многократном вызове расчета каждый раз ведь память занимает? Значит по идее перед каждым новым вызовым его тоже можно почистить?
Значит по идее перед каждым новым вызовым его тоже можно почистить?
Нужно, а не можно. Очистить.
Цитата
поправил, только вот теперь он ругается: EConvertError "" is not a valid floating point value.
Значит, не везде поправил:
if (GridResult.Cells[1, i]<>'') and (GridResult.Cells[5, i]<>'') then begin a1:=StrToFloat(GridResult.Cells[1, i]); // <--- Здесь тоже надо менять ... a2:=StrToFloat(GridResult.Cells[5, i]); // <--- И здесь ... Series1.AddXY(a1, a2, '', clRed); end;
Спасибо большое, графики отображаются, сейчас займусь чисткой буфера. Удивляюсь как вы умудряетесь замечать всё. Вот что значит мастера своего дела! Еще раз спасибо большое за помощь!
RussoTuristo, ты не думал никогда над тем, что чем меньше строк в программе - тем лучше? Вот тебе 2 хинта, как можно безо всяких проблем убрать по десятку строк в каждом случае, без изменения функционала программы.
Первый - касается вот этого ужаса (из процедуры TzoneMath.ShowOnTable):
Цитата
for i:=1 to steps do begin grid.Cells[0,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].tau,-5)); grid.Cells[1,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].Fp,-5)); grid.Cells[2,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].Gk,-5)); grid.Cells[3,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].y,-5)); grid.Cells[4,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].Qpozh,-5)); grid.Cells[5,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].Ro2,-5)); grid.Cells[6,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].T2,-5)); grid.Cells[7,i]:=FloatToStr(RoundTo(rooms[room].iParams[i-1].Gm,-5)); end;
Зачем это делать, расскажи? Что, выводить значения можно только вот таким, допотопным, "строка за строкой" способом? А понадобится тебе уменьшить точность, будешь везде "-5" изменять на "-4" что-ли?
Исправление:(Показать/Скрыть)
1) изменяем описание структуры TiParams на вот такое: TiParams = packed record yP, T2P, Ro2P, T21 : Extended; //пересчет
case Boolean of False: (tau : Extended; //текущее время (с) Fp, Gk, y, Qpozh, Ro2, T2, Gm : Extended); True : (Values : Array[0 .. 7] Of Extended); end; , то есть, вариантная запись, все те элементы, которые будут выводиться в Grid, располагаем в конце структуры в нужном порядке, и совмещаем с ними массив Extended-значений (не забудь добавить слово Packed в описание структуры, иначе вылетишь с ошибкой). А там, где было построчное добавление - один простой цикл (работаем с элементами, как с массивом, он ведь физически располагается на тех же местах, что и переменные, и обращение rooms[room].iParams[i-1].Values[0] эквивалентно rooms[room].iParams[i-1].tau, и т.д.):
for i:=1 to steps do begin for j := 0 to 7 do grid.Cells[j, i] := FloatToStr(RoundTo(rooms[room].iParams[i-1].Values[j], -5)); end;
Функционал не изменился, все работает абсолютно так же, как и раньше.
Второй. Зачем дублировать здесь:
Цитата
function TzoneMath.fGm(iter,CurrentRoom:integer; woll:TWoll; forroom:integer):extended;
function TrapezeSt1(a, b: extended; eps: extended): extended; function func(h: extended): extended; begin curroom:=CurrentRoom; Result:=Woll.Proem[0].Width * Rooms[CurrentRoom].iParams[iter].Ro2P * sqrt((2 * TrapezeInt(Rooms[CurrentRoom].Height-Rooms[CurrentRoom].iParams[iter].yP, woll.Proem[0].Height, 0.01, fdP_1))/Rooms[CurrentRoom].iParams[iter].Ro2P); end; var xx1,xx2,xx3:extended; c:integer; begin result:=0; for c:=1 to round(abs(b-a)/eps) do begin xx1:=func(a+c*eps); xx2:=func(a+c*eps+eps); if xx2>xx1 then begin xx3:=xx1 end else begin xx3:=xx2; end; result:=result+abs(xx2-xx1)*eps+abs(xx3)*eps; end; end;
begin if (Rooms[CurrentRoom].Height-Rooms[CurrentRoom].iParams[iter_buf].YP)<woll.Proem[0].Height then begin result:= TrapezeSt1(Rooms[CurrentRoom].Height-Rooms[CurrentRoom].iParams[iter].yP, Woll.Proem[0].Height, 0.01); end else begin result:=0; end; end;
то, что уже сделано в модуле intfunc? У тебя же уже есть там функция, вычисляющая интеграл. Зачем же ты ее тут опять переписываешь заново? Всё проще:
Исправление:(Показать/Скрыть)
function fdP_1(h: extended): extended; // Эта функция у тебя была... begin result:=9.81*(zoneMath.Rooms[curroom].iParams[0].Ro2P-zoneMath.Rooms[curroom].iParams[iter_buf].Ro2P) end;
// После нее добавляешь еще одну, небольшую, функцию: var currWoll : TWoll; iteration : Integer;
function SecondFunc(h: extended): extended; begin with zoneMath.Rooms[curroom] do Result:=CurrWoll.Proem[0].Width * iParams[iteration].Ro2P * sqrt( (2 * TrapezeInt(Height-iParams[iteration].yP, currwoll.Proem[0].Height, 0.01,fdP_1)) / iParams[iteration].Ro2P ); end;
function TzoneMath.fGm(iter,CurrentRoom:integer; woll:TWoll; forroom:integer):extended; begin curroom:=CurrentRoom; currWoll := woll; iteration := iter;
if (Rooms[CurrentRoom].Height-Rooms[CurrentRoom].iParams[iter_buf].YP)<woll.Proem[0].Height then begin result:= TrapezeInt(Rooms[CurrentRoom].Height-Rooms[CurrentRoom].iParams[iter].yP, Woll.Proem[0].Height, 0.01, SecondFunc); end else begin result:=0; end; end;
, и она прекрасно сделает то, что положено...
Функционал опять же, остался прежним, а если так - то зачем писАть больше? Кстати, еще один повод перейти на новую версию Дельфи. в 2009 и выше это делается через анонимные функции, избавляя тебя от необходимости добавлять вон те две глобальные переменные.
Да, и еще... Я бы подумал над переносом хотя бы части глобальных переменных в соответствующие классы (в секцию private). Скажем, curroom. Внести ее в TzoneMath, например. Так же, как и iter_buf. Подумай над этим... И "разгрузи" код, путем использования With. Его ж читать невозможно...
Дельные замечания, поработаю над исправлением, в будущем пригодится.... И вопросик: Подскажите, пожалуйста, использую для сохранения и загрузки выше указанный код, но после загрузки при попытке Расчета вылетает ошибка: "" is not a valid integer value С чем это может быть связано? Визуально пустых строчек и эдитов нигде нет, ошибка отправляет в строчку:
procedure Tf_main.Button1Click(Sender: TObject);//Функция расчета var i:integer; begin F_main.BitBtn1Click(Sender); widthXX:=StrToFloat(edit15.text); widthYX:=StrToFloat(edit13.text);
Без сохранения/загрузки всё работает нормально, что-то не так считывается?
Приводит к краху. Ибо пробел - это не число, естественно. Два исправления: во-первых (процедура Tf_main.BitBtn1Click):
if (Trim(GridRoom.Cells[2, i])<>'') and (Trim(GridRoom.Cells[3, i])<>'') then
, тогда пробел не будет пропущен, и во-вторых, при чтении из файла:
if TheClassName = 'TGrid' then with FindComponent(TheComponentName) as TStringGrid do begin ReadLn(f, R); RowCount := R; for i := 0 to R - 1 do begin ReadLn(f, s); if s <> '' then // <--- Вот эту строку добавь, чтоб лишнюю работу не делать Rows[i].Text := StringReplace(s, #9, #13#10, [rfReplaceAll]); end; end;