Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2006.08.20;
Скачать: [xml.tar.bz2];

Вниз

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

 
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 вся ветка

Форум: "WinAPI";
Текущий архив: 2006.08.20;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.56 MB
Время: 0.038 c
2-1154598822
rem2
2006-08-03 13:53
2006.08.20
Opendialog


5-1127570241
bneuro
2005-09-24 17:57
2006.08.20
Помещение в DLL своего компонента


1-1152192712
dvakar
2006-07-06 17:31
2006.08.20
Как сохранить содержимое WebBrowser на диск?


15-1153331373
Юрий Зотов
2006-07-19 21:49
2006.08.20
Что Вы думаете о буквоедах?


1-1152464349
iNV
2006-07-09 20:59
2006.08.20
Работа с XML как с реестром., Запись чтение.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский