Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.08.20;
Скачать: CL | DM;

Вниз

Постоянное разбухание памяти, занимаемой программой   Найти похожие ветки 

 
EarlVadim ©   (2006-04-24 12:22) [0]

Суть такова.
Раз в минуту программа создает массив из потоков с FreeOnTerminate=true. В самих потоках используются
stfl:=TStringList.Create и FileStream :=TFileStream.Create. В равном им количестве присутствуют  stfl.free и FileStream.free.

Результат - каждую минуту увеличение памяти на 50-100кБ.
Но что интересно, если программу свернуть в трей (для чего используется компонента TCoolTrayIcon и развернуть, то размер занимаемой памяти резко уменьшается до уровня первоначального запуска программы.
Подскажите где я мог накосорезить?


 
Rouse_ ©   (2006-04-24 12:30) [1]

Нужно код смотреть...


 
EarlVadim ©   (2006-04-24 12:40) [2]

да я в общем-то не против проект выслать, но это довольно большой код.


 
Сергей М. ©   (2006-04-24 12:45) [3]

Синхронизация (метод TThread.Synchronize) используется ?


 
EarlVadim ©   (2006-04-24 13:01) [4]

нет не используется.


 
Сергей М. ©   (2006-04-24 13:04) [5]

А что у тебя творится в основном потоке все то время, пока дополнительные что-то там делают в фоне ?


 
Игорь Шевченко ©   (2006-04-24 13:06) [6]

MemProof


 
EarlVadim ©   (2006-04-24 13:08) [7]

цикл по таймеру раз в 3000 опрашивает наличие готовых данных в property потоков. В конце каждого потока - Suspend;
Как только property READY всех потоков будет TRUE, всем потокам передается Resume, тем самым потоки заканчивают своё существование (должны) поскольку они FreeOnTerminate=true.


 
EarlVadim ©   (2006-04-24 13:09) [8]


> MemProo


Я искал в сети но я так понял что она не для Винды.  Или плохо искал...
может ссылку?


 
Сергей М. ©   (2006-04-24 13:15) [9]


> цикл по таймеру раз в 3000 опрашивает наличие готовых данных
> в property потоков


Таймер-то зачем ? Вместе с suspend"ом/resum"ом ?
Доп.поток в состоянии сам известить осн.поток о завершении своей функциональной "деятельности". На то есть событие OnTerminate и вирт.метод DoTerminate.


 
EarlVadim ©   (2006-04-24 14:06) [10]

Так мне же все-равно писать эти данные в форму... или я чего-то не понимаю.
Я раз в 3 сек. переписываю Label.Caption"ы например, пока все потоки не отработают.


 
Сергей М. ©   (2006-04-24 14:14) [11]

Поток отработав возбудит OnTerminate, обработчик которого будет вызван в контексте осн.потока, где при этом можно "переписать" все что угодно - хоть Label.Caption"ы хоть Конституцию


 
EarlVadim ©   (2006-04-24 14:22) [12]

боюсь квалификации не хватит, но может попробую. Засада для меня в том,
что все элементы в форме создаются динамически (Labels : array of TLabel и т.д.), потоки тоже. и как связать всех их - сразу как-то теряюсь.
Но в любом случае - это просто более грамотный метод чтения данных потока, а проблему-то он вряд ли решит.


 
Сергей М. ©   (2006-04-24 14:41) [13]


> как связать всех их


На то и существует упомянутый метод синхронизации.


> проблему-то он вряд ли решит


Начни с минимальной "грамотности" - пролблем ощутимо поубавится.


 
EarlVadim ©   (2006-04-24 15:46) [14]

Начать?  Ну думаю адо начать с того, что есть.
Очень упрощая код такой..........

MAINUNIT

type
 TMainForm = class(TForm)
       procedure FormShow(Sender: TObject);
       Procedure ReadData(Sender: TObject);
       procedure RxTimerEvent1Timer(Sender: TObject);
       procedure RxTimerEvent3Timer(Sender: TObject);
 private
 protected
 public
       MThr   : MyThread;
      Thread : array of MyThread;
        Labels: array of TsLabel;
     MyLabel : TsLabel;
       Gauges: array of TsGauge;
    MyGauge : TsGauge;

var
 MainForm: TMainForm;

implementation

procedure TMainForm.FormShow(Sender: TObject);
var I : integer;
begin

   { HOSTS : integer  - читаю из реестра }

   setlength(Labels, Hosts);
   setlength(Gauges, Hosts);
   setlength(Thread, Hosts);

   For i:= 0 to HOSTS-1 do begin

           MyLabel := TsLabel.Create(self);
           ........................
           Labels[I] :=  MyLabel;

           MyGauge := TsGauge.Create(self);
           ........................
           Gauges[I] :=  MyGauge;

           MThr := MyThread.Create(HostPath[i]);  // передаю UNC-путь файла
           MThr.Priority := tpLowest;
           MThr.FreeOnTerminate := true;
           MThr.Resume;
           Thread[i]:= MThr;

   end;

Procedure TMainForm.ReadData(Sender: TObject);
Var i1   : integer;
 Cycle : boolean;
Begin
    Cycle:= true;
    For i1:= 0 to Hosts-1 do  
        IF Thread[i1].Ready THEN BEGIN
                Gauges[i1].Progress:= Thread[i1].Progress;
                Labels[i1].Caption:= "Имя - "+Thread[i1].Name;
        END else Cycle:= false;
// если все потоки отработали, то флаг=true если нет=false
End;

procedure TMainForm.RxTimerEvent1Timer(Sender: TObject);
Var It : integer;
begin
      RxTimerEvent1.Enabled:= false;
      RxTimerEvent3.Enabled:= true;    
      For It:= 0 to Hosts-1 do Thread[it].Resume;
end;

procedure TMainForm.RxTimerEvent3Timer(Sender: TObject);
var I1, Ix : integer;
begin
      ReadData(Sender);
end;



MyThreadUnit


interface
MyThread = class(TThread)
private
    CF      : String;
    FName : String;
    FProg   : integer;
    FReady  : boolean;
    FCheck  : boolean;
protected
   procedure Execute; override;
public
   constructor Create(InPar : String);
   function GetReady: Boolean;
   function GetName: string;
   function GetProg: integer;

   property Check: Boolean Read FCheck Write FCheck;
   property Ready: Boolean Read GetReady;
   property Name: string Read GetName;
   property Progress: integer Read GetProg;
end;

implementation

constructor MyThread.Create(InPar : String);
begin
   CF:= InPar;
   FReady:= false;
   FCheck:= true;
   inherited Create(true);
end;

function MyThread.GetReady: boolean;
begin
   Result:= FReady;
end;
function MyThread.GetName: string;
begin
   Result:= FName;
end;
function MyThread.GetProg: integer;
begin
   Result:= FProg;
end;

procedure MyThread.Execute;
begin

While FCheck do BEGIN  
       FName:= .....;
       FProg:= ......;
       FReady:= true;

        Suspend;

        FReady:= false;
 END;
end;



 
Сергей М. ©   (2006-04-24 16:05) [15]

Код никуда не годится.

Очень много вопросов к нему.

Радикальной переделки требует практически все.


 
EarlVadim ©   (2006-04-24 16:16) [16]

Ну, любой код можно написать минимум 3-мя способами.
Мой, согласен, не займет призовых мест, но он работает.

Вот к вопросу о разбухании памяти какие-то конкретные замечания по коду  есть?
Я кстати сильно урезал метод чтения файлов в MyThreadUnit.
Именно там используется

   
    stfl:=TStringList.Create;
    FileStream :=TFileStream.Create;
    ..................
    stfl.free;
    FileStream.free;


 
Сергей М. ©   (2006-04-24 16:18) [17]


> к вопросу о разбухании памяти какие-то конкретные замечания
> по коду  есть?


Нет кода - нет и замечаний.


> Именно там используется


Именно "там" и иллюстрируй в коде.


 
EarlVadim ©   (2006-04-24 16:44) [18]

2Сергей М. ©
Нет желания сказать что-то путное, так и писать не надо.
Кроме общих фраз и "фи" пока знаний предмета не увидел.
Кто-нибудь все-таки по-существу что поправит?


 
Сергей М. ©   (2006-04-24 17:08) [19]


> знаний предмета не увидел


Ты тут "экзаменатора" не строй из себя. Рано еще, судя по алгоритму.

Хочешь "что-то путное" ?

Выеладывай ключевые моменты алгоритма, скрытые под "..................." в [16].

Про крит.секции, которые ты напрочь игнорируешь, потом поговорим.


 
EarlVadim ©   (2006-04-24 18:00) [20]


procedure MyThread.Execute;
begin
   While FCheck do BEGIN

       STFL:= TStringList.Create;

       If FileExists(CF) then begin
              try
                 FileStream := TFileStream.Create(PChar(CF),
                      fmOpenRead or fmShareDenyRead);
              finally
                    try
                          STFL.LoadFromStream(FileStream);
                    finally                      
                          FName:= STFL.Strings[0];
                          FProg:= StrToIntDef(STFL.Strings[1],0);
                    end;
                    FileStream.Free;
              end;
             
           end;
     STFL.Free;
     FReady:= true;

     Suspend;

     FReady:= false;
  END;
end;



 
sniknik ©   (2006-04-24 18:31) [21]

> Suspend;
????? внутри Execute, а как же сработает FreeOnTerminate=true ?

и несущественное, нафига создавать STFL еще не зная понадобится он или нет?
и посущественнее, обработки ошибок нет.


 
EarlVadim ©   (2006-04-24 18:53) [22]


> а как же сработает FreeOnTerminate=true

Он сработает один раз, когда программа завершится.
В OnClose передав в потоки

Thread[i].Check:= false;
Thread[i].Resume;



> нафига создавать STFL

Логично, не задумывался. Изменю.


> обработки ошибок нет

Так случаев фатальных ошибок с вылетом пока небыло в этом месте.
Если чтение из файла не состоялось, принимаются значения по умолчанию.
Обе Free отрабатывют, а память растёт.


 
sniknik ©   (2006-04-24 21:42) [23]

> Он сработает один раз, когда программа завершится.
ну и что ты тогда хочеш в процессе работы? жди пока программа завершится... и осводит потоки.
и надейся что нет путаници, что не делаеш Resume какому нибудь потоку раньше чем он отработал и установил Suspend...

кстати зачем цикл? если поток строго только 1 раз отрабатывает. зачем дополнительная переменная выхода из цикла, во первых все одно один раз работает, на Suspend застопорится, во вторых есть стандартная Terminated и метод установки Terminate. и зачем вообще ждать пока отработают все потоки перед завершением? пусть бы себе отрабатывали да закрывались...
не пойму, с логикой чтото запутано/замудрено.

> Так случаев фатальных ошибок с вылетом пока небыло в этом месте.
обработка должна быть на тот случай когда будут... сэмулируй, закрой права на чтение/открой в другом месте эксклюзивно  и помосмотри что будет...  обработка как раз чтобы этого не было.


 
Slym ©   (2006-04-25 04:53) [24]

EarlVadim ©   (24.04.06 18:00) [20]
1. STFL.Strings[0]; - Outofbounds :)
2. sniknik ©   (24.04.06 18:31) [21]
нафига создавать STFL еще не зная понадобится он или нет?

И это верно
3. зачем If FileExists(CF) then begin если всеравно в try оборачиваешь?
4. Вложенные finally сложновато...
5. STFL.Free; не защищен finally...
6. Suspend внутри не есть гуд


 
Slym ©   (2006-04-25 05:05) [25]

7. Ты конечно об этом не думал, но твой файл может оказать ся не "твоим", а каким-нибудь "c:\films\porno.avi" 700Мб, а ты его в TStringList! памяти покушает :) лучше смотреть в сторону ReadLn
function ReadLn(Stream:TStream):string;
const cCR = #13; cLF = #10; cEOF = #26;
var Ch:Char;
begin
 result:="";
 while Stream.Read(Ch,1)>0 do
 begin
   if Ch=cLF then break;
   if Ch=cEOF then break;
   if Ch<>cCR then
   begin
     result:=result+Ch;
     continue;
   end;
   if Stream.Read(Ch,1)=0 then break;
   if Ch=cLF then break;
   if Ch=cEOF then break;
   result:=result+cCR+Ch;
 end;
end;

procedure Execute;
var
FileStream:TFileStream;
begin
  While FCheck do
  try
    FileStream:=TFileStream.Create(PChar(CF),fmOpenRead or fmShareDenyRead);
    try
      FName:=ReadLn(FileStream);
      FProg:=StrToIntDef(ReadLn(FileStream),0);
    finally
      FileStream.Free;
    end;
    FReady:= true;
  except
    FReady:= false;
  END;
  Suspend;
end;


 
EarlVadim ©   (2006-04-25 11:04) [26]

Поясню ещё немного.

Поток, отработав засыпает - Suspend.
Но через минуту, по таймеру основного потока получает Resume и отрабатывает полностью с самого начала.
В этот момент в основном потоке таймер Enabled=false.
Когда основной поток увидит, что все дочерние потоки отработали и заснули, он снова запустит таймер на 1 минуту.
Это ответ на вопрос о логике. Что касается эмуляции ошибки, то до них ещё просто не добрался. Все критические моменты программы я довольно чётко понимаю. Но на некоторые я временно "забил".

Что касается длины файлов, то я точно знаю, что это за файлы. И точно знаю в какой момент их можно читать. Так что здесь мин нет.

А вообще я впервые остановился и посмотрел на свой код немного со стороны и вынужден согласится с товарищем, который ничего конкретного не посоветовал, зато прав оказался в главном. Код буду переписывать с нуля.
Основной смысл - потоки должны умирать. а через минуту буду создавать новые и так далее.


 
evvcom ©   (2006-04-25 11:25) [27]


> Все критические моменты программы я довольно чётко понимаю.

Ой ли?

> Основной смысл - потоки должны умирать. а через минуту буду
> создавать новые и так далее.

Неправильно ты понял основной смысл. Более основным смыслом было желание тебе сказать, что поток может сам информировать основной поток о завершении части задачи ему предназначенной (см. Synchronize, Post/SendMessage, другие пока не надо). И совсем не обязательно, что после этого он должен умереть. Может и уснуть. А вот использование таймеров здесь неоправдано. И постоянные циклы (хоть и происходящие с паузами) по проверке состояний ни к чему.


 
EarlVadim ©   (2006-04-25 12:41) [28]

С Synchronize попробую.
В инете встречал, даже пробовал в варианте со статичной парой поток-элемент. работало. Почему не пошёл дальше даже уже не помню.
Убиванием потока я попытаюсь освобождать память занимаемую им вместе со всеми его переменным, потому что точно знаю, что жрут память у меня именно потоки.

А вот без таймера никак.
Хотя можно в конце цикла ставить не Suspend а Sleep(60000).


 
Slym ©   (2006-04-25 12:53) [29]

EarlVadim ©   (25.04.06 12:41) [28]
Чушь! и gосле закрытия программы, эта самая программа будет висет в поцессах 60 сек... с опцией "Не отвичает"

Если надо уснуть то Event.WaitFor(60000) и если нужно досрочно разбудить... Event.PulseEvent


 
Сергей М. ©   (2006-04-25 12:53) [30]


> EarlVadim ©   (25.04.06 12:41) [28]


> потому что точно знаю, что жрут память у меня именно потоки.


Это ты обнаружил под отладчиком ?
Или это твои "умозаключения" ?

Ты вообще пользуешься ли отладчиком для решения своих проблем ?


 
EarlVadim ©   (2006-04-25 14:07) [31]

почему не пользуюсь, под отладчиком все шоколадно.
Перед Suspend все динамические переменные потоков в nil.
А память тогда где?


 
Сергей М. ©   (2006-04-26 08:26) [32]


> EarlVadim ©   (25.04.06 14:07) [31]


> память тогда где?


Ты хоть раз получил Out of memory ?

Если утечка действительно имеет место быть, то при наблюдаемой тобой динамике наращивания размера потребляемых ресурсов памяти исключение произойдет довольно скоро ...


 
EarlVadim ©   (2006-04-26 09:29) [33]

До Out of memory не доходит. Завершаю раньше.
Когда я утром прихожу на работу и вижу что моя программа вместо 10Мб при старте занимает 250Мб, то не надо быть семи пядей во лбу чтобы понять что это ненормально.


 
Сергей М. ©   (2006-04-26 09:51) [34]


> вместо 10Мб при старте занимает 250Мб


И все это время программа была "свернута в трей" ?


 
Slym ©   (2006-04-27 06:17) [35]

Кстати кроме памяти (физической), TaskManager умеет показывать другие показатели которые иногда более информативны: виртуальная память, счетчик потоков/дескрипторов/объектов
судя по всему у тебя пухнет счетчик потоков



Страницы: 1 вся ветка

Текущий архив: 2006.08.20;
Скачать: CL | DM;

Наверх




Память: 0.58 MB
Время: 0.038 c
4-1146320331
h8394E
2006-04-29 18:18
2006.08.20
Типы контролов


15-1153654286
Firefly
2006-07-23 15:31
2006.08.20
ТЗ


3-1149682677
Krugly
2006-06-07 16:17
2006.08.20
Добавление записи в таблицу FoxPro из Delphi


1-1152023599
DancerMan
2006-07-04 18:33
2006.08.20
Не запускается exe-шник


9-1132873549
Юзерок
2005-11-25 02:05
2006.08.20
directX