Форум: "Система";
Текущий архив: 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.006 c