Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 18.09.2013, 06:48
Creator13 Creator13 вне форума
Прохожий
 
Регистрация: 18.09.2013
Сообщения: 15
Версия Delphi: Delphi 7
Репутация: 10
Восклицание Утечка памяти

Доброго времени суток, уважаемые программисты.
Пишу программку - анализатор картинок.

На форме есть таймер с интервалом времени в 1с
Каждую секунду таймер делает скриншот экрана и анализирует полученную картинку
Ищутся определенные вхождения на скрине и сравниваются с Image'ами, которые просто лежат на форме с загруженными картинками Если находит вхождение - заносятся данные в Edit'ы и Lable'ы
Все бы хорошо. Программа работает на отлично около часа-полтора, а потом начинаются зависоны...
В конечном итоге табличка "out of sysyem resource" и все встает... Иногда прогу вышибает(сама закрывается)
Хотя никаких завершений в Timer1 не прописано и работает только он один. В нем только циклический скрин и сравнения.
По диспетчеру задач смотрю программа стабильно по-немногу, набирает память..
Хотя по идем должна быть "очистка" и обнуление буфера,если я правильно понимаю. Помогите пожалуйста.

Ниже код:
Код:
uses
  Windows.....;

type
    FRes = record
    found: boolean;
    x,y: integer;

  private
    { Private declarations }
  public
    { Public declarations }
  end;
     TBuf = array of array of integer;

var
  FindResult: FRes;
  buf1, buf2: TBuf;

procedure ScreenShot(var buffer: TBuf; img: TImage);
var
  x,y,c: integer;
  p: pByteArray;
  bmp:TBitmap;
begin
    bmp := TBitmap.Create;
    bmp.Width := Screen.Width;
    bmp.Height := Screen.Height;;
    BitBlt(bmp.Canvas.Handle, 0,0, Screen.Width, Screen.Height,GetDC(0), 0,0,SRCCOPY);
    img.Picture.Assign(bmp);
    img.Picture.Bitmap.PixelFormat:=pf24Bit;
    SetLength(buffer, img.Height, img.Width);
    for y:=0 to img.Height-1 do begin
    p:=img.Picture.Bitmap.ScanLine[y];
    for x:=0 to img.Width-1 do begin
     c:=((p[x*3+0] shl 8+p[x*3+1]) shl 8)+p[x*3+2];
     buffer[y,x]:=c;
    end;
  end;
    bmp.Free;
end;

procedure ReadIMG(var buffer: TBuf; img: TImage);
var
  x,y,c: integer;
  p: pByteArray;
begin
  img.Picture.Bitmap.PixelFormat:=pf24Bit; // pf8Bit;
  SetLength(buffer, img.Height, img.Width);
  for y:=0 to img.Height-1 do begin
    p:=img.Picture.Bitmap.ScanLine[y];
    for x:=0 to img.Width-1 do begin
      c:=((p[x*3+0] shl 8+p[x*3+1]) shl 8)+p[x*3+2];
      buffer[y,x]:=c;
    end;
  end;
end;

function CompareIMGS(Im1:TImage; Im2:TImage): FRes;
var
  y, x, yy, xx: integer;
begin
  ReadIMG(buf2,Im2);
  y:=0;
  repeat
    x:=0;
    repeat
      Result.found:=true;
      yy:=0;
      repeat
        xx:=0;
        repeat
          if buf1[y+yy, x+xx]<>buf2[yy,xx] then Result.found:=false;
          inc(xx);
        until (xx>=Im2.Width) or (Not Result.found);
        inc(yy);
      until (yy>=Im2.Height) or (Not Result.found);
      inc(x);
    until (x>Im1.Width-Im2.Width) or (Result.found);
    inc(y);
  until (y>Im1.Height-Im2.Height) or (Result.found);
  if Result.found then begin
    Result.x:=x-1;
    Result.y:=y-1;
  end;
end;

procedure TForm1.T_FightTimer(Sender: TObject);
begin
 ScreenShot(buf1,Image_ScreenShot);  //скриншот
 
 FindResult:=CompareIMGS(Image_ScreenShot,I_apple); //имейдж apple загруженный лежит на форме
 if FindResult.found then edit1.text:='У Вас яблоко!';

 // тут ... ниже, вот таких последних двух строчек сравнений, в теле таймера, порядка 25 штук (25 сравнений) 

end;

Спасибо!
Ответить с цитированием
  #2  
Старый 18.09.2013, 07:09
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

25 штук за 1с? Оригинально :-) Может просто не успевает отрабатывать таймер и циклится повторно? Поробуйте в начале процедуры таймер отключать, а в конце снова его запускать.
Ответить с цитированием
  #3  
Старый 18.09.2013, 07:14
Creator13 Creator13 вне форума
Прохожий
 
Регистрация: 18.09.2013
Сообщения: 15
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Да 25 сравнений. На удивление все быстро и отлично работает и сравнивает... Только трабл с ресурсами после часа, полтора работы
Ответить с цитированием
  #4  
Старый 18.09.2013, 09:38
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

Собрал на D7 и прогнал под W7 этот код (http://zalil.ru/34729896) в течении несколько часов - утечка была из-за массивов типа TBuf, может и не правильно это, но помогло обнуление в конце выполнения функции CompareIMGS массивов buf1 и buf2.
Ответить с цитированием
Этот пользователь сказал Спасибо Alegun за это полезное сообщение:
Creator13 (18.09.2013)
  #5  
Старый 18.09.2013, 09:51
Creator13 Creator13 вне форума
Прохожий
 
Регистрация: 18.09.2013
Сообщения: 15
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Опаа.... Огроменное тебе спасибо.

Нашел ссылочку сейчас скачаю.
Ответить с цитированием
  #6  
Старый 18.09.2013, 09:57
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

Утечки по 4к за цикл прекратились, во всяком случае за 3 часа работы больше 7Мб сборка так и не слопала.

Последний раз редактировалось Alegun, 18.09.2013 в 10:06.
Ответить с цитированием
  #7  
Старый 18.09.2013, 10:01
Creator13 Creator13 вне форума
Прохожий
 
Регистрация: 18.09.2013
Сообщения: 15
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Поставил в конце функции CompareIMGS как посоветовал.
SetLength(buf1, 1, 1);
SetLength(buf2, 1, 1);

Вылез Exeption. Видимо после 1го сравнения буфер пропал а на втором следующем в таймере сравнении уже он его не нашел.

Поставил такое зануление в конце всех сравнений в таймере

procedure TForm1.TTimer1(Sender: TObject);
begin
//......................CompareIMGS
//............CompareIMGS
//...

SetLength(buf1, 1, 1);
SetLength(buf2, 1, 1)
end;

Сейчас буду тестить...
Или при этом способе тоже будет утекать?

Последний раз редактировалось Creator13, 18.09.2013 в 10:04.
Ответить с цитированием
  #8  
Старый 18.09.2013, 11:16
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

Да, срабатывает только раз, если сравнений больше одного, утечки продолжаются, но если "обнуление" массива делать в процедурах
Код:
//ScreenShot
...
SetLength(buf1,1,1);
SetLength(buffer, img.Height, img.Width);
...
и

Код:
//ReadIMG
...
SetLength(buf2,1,1);
SetLength(buffer, img.Height, img.Width);
... 
то это вроде поможет и ошибок не возникнет (не должно)
Ответить с цитированием
Этот пользователь сказал Спасибо Alegun за это полезное сообщение:
Creator13 (18.09.2013)
  #9  
Старый 18.09.2013, 11:36
Creator13 Creator13 вне форума
Прохожий
 
Регистрация: 18.09.2013
Сообщения: 15
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Код:
procedure ScreenShot(var buffer: TBuf; img: TImage);
var
  bmp:TBitmap;
  DCtemp:HDC;
begin
try
    DCtemp:=getDC(0);
    bmp := TBitmap.Create;
    bmp.Width := Screen.Width;
    bmp.Height := Screen.Height;;
    BitBlt(bmp.Canvas.Handle, 0,0, Screen.Width, Screen.Height,DCtemp, 0,0,SRCCOPY);
    img.Picture.Assign(bmp);
    ReadIMG(buffer,img);
 finally
    bmp.Free;
    ReleaseDC(0, DCtemp);
  end;
end;

Еще подправил процедуру скрина.
Подсказали, что есть GetDC, но не было ReleaseDC
Буду тестить.
Ответить с цитированием
  #10  
Старый 18.09.2013, 19:42
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

Хорошая мысля приходит опосля, действительно, это про релиз
Здесь ещё желательна небольшая перетасовка строк -
Код:
...
 bmp := TBitmap.Create;
  try
   ...
   DCtemp:=getDC(0);
   BitBlt...
   ReleaseDC(0, DCtemp);
   ...
  finally
   bmp.Free;
  end;
...
так как-то правильнее что-ли...
Ответить с цитированием
Этот пользователь сказал Спасибо Alegun за это полезное сообщение:
Creator13 (19.09.2013)
  #11  
Старый 19.09.2013, 07:56
Creator13 Creator13 вне форума
Прохожий
 
Регистрация: 18.09.2013
Сообщения: 15
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Часов 6-7 работало все на ура) без проблем!
Спасибо.
Ответить с цитированием
  #12  
Старый 25.09.2013, 08:16
Creator13 Creator13 вне форума
Прохожий
 
Регистрация: 18.09.2013
Сообщения: 15
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Тут мне подсказали что если действие происходит многократно одно и тоже (например в таймере) то длину массива каждый раз задавать грех.
Нужно определить разрешение экрана и 1 раз по нему задать длину массива.

Кто что думаешь по этому поводу?
Ответить с цитированием
  #13  
Старый 25.09.2013, 09:09
Аватар для xdessx
xdessx xdessx вне форума
Заблокирован
 
Регистрация: 23.09.2013
Адрес: Астана
Сообщения: 34
Версия Delphi: Delphi 7
Репутация: -1244
По умолчанию

Я вот сижу и непонимаю как память может утечь?? Мб у тебя ее украли??? У нас в школе часто планки воруют
Ответить с цитированием
  #14  
Старый 25.09.2013, 11:04
Аватар для Freeman
Freeman Freeman вне форума
Местный
 
Регистрация: 05.10.2012
Адрес: Санкт-Петербург
Сообщения: 577
Версия Delphi: 6
Репутация: выкл
По умолчанию

Работа с таймером -- неявная многопоточность. Пользоваться при этом глобальными переменными -- тяжкий грех.
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 06:47.


 

Сайт

Форум

FAQ

Соглашения

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2025