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

Вниз

Глюки, связанные с TListView и памятью   Найти похожие ветки 

 
Smok_er   (2002-05-29 13:10) [0]

Уважаемые мастера!
Помогите пожалуйста.
Я пишу дипломную работу - анализ логфайлов Apache, результаты анализа вывожу в сабже. После вывода очередной статистики сильно заполняется память, причем по какой-то непонятной мне причине память от предыдушего просмотра совершенно другой статистики не освобождается (использую метод Clear).
В результате, после 3-4 просмотров появляется ошибка Out of resources и винда начинает конкретно глючить.
В принципе, не пойму еще и то, почему не освобождается память TStringList"a. Т.е., при использовании что метода Free, что более жесткого Destroy - память, используемая программой не уменьшается :(
Может быть кто-то знает, как с этим бороться?


 
Digitman   (2002-05-29 13:35) [1]

Ну и как ты себе мыслишь это - без оригинального кода сказать тебе, что и где ты там натворил некорректно ?


 
Smok_er   (2002-05-29 13:56) [2]

ОК!
Вот код вывода в ListView статистики, например по User-Agent"ам.
Вся остальная выводится также.
Причем основной глюк приходится на тот момент, когда я прокручиваю scroll bar.
Т.е. память под программу резко увеличивается, а после перехода на другую статистику не уменьшается.
В данном примере в ListView выводится порядка 400 записей.
PrepareListView;
NewColumn := frMain.lvReports.Columns.Add;
NewColumn.Caption := "User-Agent";
NewColumn := frMain.lvReports.Columns.Add;
NewColumn.Caption := "Hits";
frMain.lvReports.Columns.Items[0].Width:= frMain.lvReports.Width-60-20;
frMain.lvReports.Columns.Items[1].Width:= 60;
frMain.lvReports.Items.BeginUpdate;
for i:=Low(UserAgent) to High(UserAgent) do
begin
ListItem := frMain.lvReports.Items.Add;
ListItem.Caption := UserAgent[i].Name;
ListItem.SubItems.Add(IntToStr(UserAgent[i].Hits));
end;
frMain.lvReports.Items.EndUpdate;


 
NailS   (2002-05-29 16:48) [3]

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


 
Smok_er   (2002-05-29 17:05) [4]

Так UserAgent постоянно сидит в памяти.
Он сформировался после обработки лога.

Вот в другом я точно уверен. В данном примере str не освобождается почему-то :(
str:= TStringList.Create;
...
... Операции над этим листом
...
str.Free;

И еще одна непонятка - на форме установлен Splitter. Так вот почему то при его движении постоянно идет прибавление памяти, расходуемой программой. Т.е., например, если его дернуть раз 50, то память прибавляется метров на 5 до тех пор, пока не вылезет мессага "Out of Resources"

Господа, выручайте, как бороться с этим недугом?


 
NailS   (2002-05-29 17:54) [5]


> Вот в другом я точно уверен. В данном примере str не освобождается
> почему-то :(
> str:= TStringList.Create;
> ...
> ... Операции над этим листом
> ...
> str.Free;


Бред какой-то. Чудес не бывает. Попробуй мемпруфом посмотреть утечки памяти.
http://www.automatedqa.com/downloads/memproof.asp


> Так вот почему то при его движении постоянно идет прибавление
> памяти, расходуемой программой. Т.е., например, если его
> дернуть раз 50, то память прибавляется метров на 5 до тех
> пор, пока не вылезет мессага "Out of Resources"

А случаем на OnCustomDraw... ничего не делаешь?


 
Digitman   (2002-05-29 18:23) [6]

1.какие события сплиттера и ListView обрабатываешь ? Где код ?
Опять гадать будем ?

2.
str.Free выполняется ? ты ловил брейкпойнт на этой строчке ?


 
Smok_er   (2002-05-29 23:11) [7]

2 Nails
Уже качаю...
Нет, абсолютно ничего
просто treeview и listview со сплиттером.
Сам в шоке.
Причем память растет только в том случае, если в листвью есть какие-то данные (либо они там были вообще). Т.е. методом clear происходит только видимое очищение, а на самом деле память не высвобождается.

2Digitman
Обрабатываю только одно событие от тривью
но мне кажется, что дело не в этом.
вот код:
procedure TfrMain.ReportsClick(Sender: TObject);
begin
case Reports.Selected.ImageIndex of
101: Report.BasicStatistics;
103: Report.MostActiveDays;
104: Report.MostActiveHours;
106: Report.MostActiveMonths;
107: Report.DetailDailyActivity;

123: Report.MostCommonReferrerSites;
124: Report.MostCommonReferrerURLs;
128: Report.SearchPhrases;

134: Report.MostUserBrowsers;
136: Report.OnlineBrowsers;
137: Report.OfflineBrowsers;

138: Report.DownloadManagers;
142: Report.UserAgents;
end;
end;


Для удобства последующей русcификации для наших профессоров я использую imageindex для определения, куда кликнул.
Сам код одного из таких отчетов приведен выше.
str.Free выполняется, никаких ошибок не выдает.
пробовал и чистить перед удалением - ничего не помогло.


 
Smok_er   (2002-05-30 00:54) [8]

Блин, ну я тут намутил воду.
А Nails верно задал резонный вопрос, на который я опрометчиво ответил нет :(
Да, я совсем забыл
У тривью я раскрашиваю ячейки в разные цвета как раз методом OnCustomDraw
Но отчего тогда такое происходит при использовании этого метода? Или это очередная корявость инпрайза?


 
int64   (2002-05-30 05:44) [9]

А ты уверен, что и на этот раз правильно локализовал ошибку?
Отключи OnCustomDraw и посмотри: есть утечка.
Если есть, код в студию.

В TListView проблем с утечкой нет - всё коректно удаляется.
Это ты что-то намутил; с UserAgent например.


 
NailS   (2002-05-30 11:33) [10]

Когда смотришь за памятью следи в Диспетчере задач, то наблюдай за виртуальной памятью, этот параметр более информативный, чем используемая память при ловле утечки


 
[aka]   (2002-05-30 13:05) [11]

Почти наверняка "текущий" OnCustomDraw. Если выделяешь и хранишь объекты в TTreeNode.Data, то TTreeNodes.Clear не вызывает OnDelete для нод, так что там утечка тожа гарантирована.


 
Smok_er   (2002-05-30 13:29) [12]


procedure TfrMain.lvReportsAdvancedCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; Stage: TCustomDrawStage;
var DefaultDraw: Boolean);
begin
if isURL(Item.Caption) then
begin
(Sender as TListView).Canvas.Font.Color:= $683E3E;
(Sender as TListView).Canvas.Font.Style:= [fsUnderline];
end;

if (Item.Index mod 2) = 0 then
(Sender as TListView).Canvas.Brush.Color:= $EAFFFF
else
(Sender as TListView).Canvas.Brush.Color:= clWhite;
end;

procedure TfrMain.lvReportsAdvancedCustomDrawSubItem(
Sender: TCustomListView; Item: TListItem; SubItem: Integer;
State: TCustomDrawState; Stage: TCustomDrawStage;
var DefaultDraw: Boolean);
begin
(Sender as TListView).Canvas.Font.Color:= clBlack;
(Sender as TListView).Canvas.Font.Style:= [];
if (Item.Index mod 2) = 0 then
(Sender as TListView).Canvas.Brush.Color:= $EAFFFF else
(Sender as TListView).Canvas.Brush.Color:= clWhite;
end;



Все дело именно в customdraw
Как только я закомментировал эти 2 события, то глюки сразу прекратились.
Кстати, был вынужден использовать именно 2 события из-за невозможности (во всяком случае у меня не получилось) не выделять всю строку листвью, а только отдельные ячейки, удовлетворяющие какому-то условию.
В данном случае у меня идет проверка на URL и в случае варианта, если текст в ячейки - ссылка, то выделение среди остальных ячеек.
Причем остальные ячейки в этой строке не должны выделяться


 
NailS   (2002-05-30 13:51) [13]

Не разу не видел, чтобы простое присвоение колора и фонта приводило к MemoryLeak, запости сюда функцию isURL, меня терзают смутные сомнения на ее счет.


 
AlexSV   (2002-05-30 14:34) [14]

В свое время в конференции обсуждался аналогичный вопрос.

Собственно вопрос:
> Есть у меня ListView у него например 3-и колонки и свойство
> ViewStyle=vsReport. Запихиваем туда порядка 200 пунктов среди которых
> бальшинство пунктов с русским названием. В обработчике OnCustomDrawItem
> пишем одну строку
> Sender.Canvas.Font.Color:=clred
> Запускаем приложение. Естественно все 200 пунктов у список не помещаются,
> автоматом возникает полоса прокрутки. Выбираем первый пункт и затем раз
> 20-30 нажимаем Ctrl+End Ctrl+Home
> т.е. туда сюда. Так вот после очередного нажатия Ctrl+End Ctrl+Home пункты
> перерисовываются очень медленно и вместо названий пунктов появляются
> квадратики, будто шрифт не русский. Самое интересное, что иконки с русскими
> названиями, на рабочем столе тоже становятся не читабельны.
> После выхода из программы иконки на рабочем столе восстанавливают свой
> прежний вид.

Привожу ответ, может поможет:

Это ошибка в обработчике CN_Notify:
ComCtrls.pas: TCustomListView.CNNotify

Найдите это место:

if GetObject(FCanvas.Font.Handle, SizeOf(LogFont), @LogFont) <> 0 then
begin
FCanvas.Handle := 0; // disconnect from hdc
// don"t delete the stock font
SelectObject(hdc, CreateFontIndirect(LogFont));
Result := Result or CDRF_NEWFONT;
end;

Всякий раз при изменении TListView.Canvas будет расходоваться память
Можно это поправить примерно так:

if GetObject(FCanvas.Font.Handle, SizeOf(LogFont), @LogFont) <> 0 then
begin
FCanvas.Handle := 0; // disconnect from hdc
// don"t delete the stock font
if FNewFont <> 0 then DeleteObject(FNewFont);
FNewFont := CreateFontIndirect(LogFont);
SelectObject(hdc, FNewFont);
Result := Result or CDRF_NEWFONT;
end;
Для этого потребуется в описании класса TCustomListView добавить
переменную FNewFont: HGDIObj

То же самое касается TCustomTreeView - та же функция, та же ошибка.

Скопируйте измененный ComCtrls.pas в каталог с проектом.

----
© Андрей А. Лобанов <loba@nersa.ee>
NERSA Limited


 
Smok_er   (2002-05-30 15:37) [15]

Спасибо большое за ответы, но только что опробовал - не помогло. Дергаю прокруткой, сплиттером - и происходит бешенная накрутка памяти до тех пор, пока не начинаются конкретные глюки.
Вот функция isURL:

function IsURL(StringForCheck: String): Boolean;
begin
if Pos("http://",StringForCheck)=1 then
Result:=True
else Result:= False;
end;


Проще не бывает. Здесь я вижу 2 подхода - либо как-то оптимизировать обработчик события, либо отказаться от него вообще.
Не думаю, что на сдаче дипломной ко мне придерутся из-за того, что ячейки не раскрашиваются в разные цвета.
Разве что самому интересно найти правильное решение.


 
NailS   (2002-05-30 15:45) [16]

Попробуй сменить описание функции на
function IsURL(const StringForCheck: String): Boolean;

У меня был случай, когда это помогло. Хотя здесь ...незнаю.


 
Smok_er   (2002-05-30 16:14) [17]

Нет, не помогло.
Здесь на 100% видно, что причина - CustomDraw
Почему-то не освобождается память после использования, даже сделав так, как советует AlexSV


 
NailS   (2002-05-30 16:43) [18]

Собрал тестовый проект с твоими обработчиками, загнал 40000 записей, все работает. Память вроде не жрет.
Что говорит MemProof?
И что под всеми этими системами схожая ситуация?
>Win95/98, WinME, NT4, Win2k, WinXP


 
Smok_er   (2002-05-30 17:44) [19]

Нет, глючит под 98,2000 и ХР - это проверено
Остальные, догадываюсь, тоже самое
А можно глянуть на этот проект?
Желательно попробовать его запустить у себя

А по MemProof не нашел документацию.
Видно, что память сжирается, а как посмотреть куда - так и не узнал. Могу только сказать, что на указатели (Pointers)


 
NailS   (2002-05-30 18:08) [20]

MemProof показывает даже место где память была выделена и собрать проект надо с TD32 Info пути к исходникам настраиваются в Options/Search Directories

Сам проект

unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls, ExtCtrls;

type
TForm1 = class(TForm)
Panel1: TPanel;
Panel2: TPanel;
lv: TListView;
Button1: TButton;
Button2: TButton;
Splitter1: TSplitter;
Panel3: TPanel;
procedure lvAdvancedCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; Stage: TCustomDrawStage;
var DefaultDraw: Boolean);
procedure lvAdvancedCustomDrawSubItem(Sender: TCustomListView;
Item: TListItem; SubItem: Integer; State: TCustomDrawState;
Stage: TCustomDrawStage; var DefaultDraw: Boolean);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

function IsURL(StringForCheck: String): Boolean;

implementation

{$R *.DFM}

procedure TForm1.lvAdvancedCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; Stage: TCustomDrawStage;
var DefaultDraw: Boolean);
begin
if isURL(Item.Caption) then
begin
(Sender as TListView).Canvas.Font.Color:= $683E3E;
(Sender as TListView).Canvas.Font.Style:= [fsUnderline];
end;

if (Item.Index mod 2) = 0 then
(Sender as TListView).Canvas.Brush.Color:= $EAFFFF
else
(Sender as TListView).Canvas.Brush.Color:= clWhite;

end;

procedure TForm1.lvAdvancedCustomDrawSubItem(Sender: TCustomListView;
Item: TListItem; SubItem: Integer; State: TCustomDrawState;
Stage: TCustomDrawStage; var DefaultDraw: Boolean);
begin
(Sender as TListView).Canvas.Font.Color:= clBlack;
(Sender as TListView).Canvas.Font.Style:= [];
if (Item.Index mod 2) = 0 then
(Sender as TListView).Canvas.Brush.Color:= $EAFFFF else
(Sender as TListView).Canvas.Brush.Color:= clWhite;
end;


function IsURL(StringForCheck: String): Boolean;
begin
if Pos("http://",StringForCheck)=1 then
Result:=True
else Result:= False;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
i : integer;
ListItem : TListItem;
begin
i := 0;
lv.Items.BeginUpdate;
while i < 40000 do
begin
ListItem := lv.Items.Add;
ListItem.Caption := " http://www.123.com";
ListItem.SubItems.Add(Format("test %d",[i]));
Inc(i);
end;
lv.Items.EndUpdate;

end;

procedure TForm1.Button2Click(Sender: TObject);
begin
lv.Items.BeginUpdate;
lv.Items.Clear;
lv.Items.EndUpdate;
end;

end.


 
Smok_er   (2002-05-31 01:01) [21]

Не удобно склепать проект.
Не понятно, где находится сплиттер и листвью. А здесь это важно. Можешь закинуть на tomachinsky@inbox.ru?
Возможно глючит из-за того, что у меня в ячейках значения, которые в них не помещаются. Хотя вряд ли.

Да, MemProof это сила!
Попробую объяснить свою проблему.
Дело в том, что я использую TStringList для более удобного добавления записей, например рефереров или useragent"ов.
Причем ввиду неэффективности использования метода IndexOf приходится сначала заполнять стринглист записями (некторые реферереры занимают по 512 символов). Получается, что я сначала заполняю его, а только потом сортирую с использованием сортировки и прохода с начала до конца на соответствие подряд идущих записей. В связи с этим резонный вопрос - есть ли более эффективный и самое главное как можно быстрый способ определения наличия соответствующей записи?
И встречный вопрос - если сразу после создания стринглиста его отсортировать, то новые записи будут добавляться с учетом сортировки или в самый конец?


 
Smok_er   (2002-06-06 00:11) [22]

Nails, извини что так долго не отвечал, были проблемы с инетом.
Получил твое письмо, большое спасибо!
Скомпилировал, долго ждал результата заполнения листвью, и в принципе опятьже появились проблемы с увеличением памяти, только не в таких пределах. Я думаю, что в моем случае проблема в том, что данные не вмещаются в ячейки...
Кстати, еще одна особенность - при достижении определенного объема памяти, расходуемого программой, последующее наращивание не происходит, как ни дергать скроллбары.
Я в конце концов отказался от всякой красоты, но все равно очень интересно, почему память не освобождается после вызова метода CustomDraw. И опять же... В твоем примере после нескольких прокруток память увеличилась примерно на 4 Мб, и мне кажется, что это многовато.


 
NailS   (2002-06-06 11:05) [23]


> твоем примере после нескольких прокруток память увеличилась
> примерно на 4 Мб, и мне кажется, что это многовато.

Честно говоря, такого эффекта не наблюдал.
Ты как за памятью смотришь?
Если в TaskManagere параметр Память, то просто сверни приложение и будешь приятно удивлен ;)



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

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

Наверх




Память: 0.52 MB
Время: 0.007 c
1-60669
MikeFW
2002-08-06 11:07
2002.08.19
Как программно переходить по закладкам TPageControl?


8-60754
SerVS
2002-04-14 02:34
2002.08.19
BMP -> JPEG


1-60695
Roman002
2002-08-06 04:58
2002.08.19
Сервис для TN


3-60521
Well
2002-07-30 11:55
2002.08.19
Как получить значение поля MEMO


7-60884
МИФИст
2002-06-04 22:44
2002.08.19
Помогите с заполнением структуры...





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский