*更新: 2 人の人が、実際の/完全なコードがなければ、私を助けるのは難しいと言いました. ほとんどは下にありますが、何か忘れた場合はここにあります。Laserrental.ca/MemoryProblem.zip
使用されている Delphi のバージョン: 2007
こんにちは、
私はスレッドと仮想リストビューが初めてなので、問題は簡単に解決できるかもしれません。しかし、私は数日間立ち往生しています。基本的に、ここに私が持っているものがあります:
http://image.noelshack.com/fichiers/2012/32/1344440638-urlsloader.png
ユーザーが [ URL の読み込み]をクリックすると、URL が次のレコードに保存されます。
type TVirtualList=record
Item:Integer; // Index
SubItem1:String; // Status
SubItem2:String; // URL
end;
...
var
LURLs : Array of TVirtualList;
そして、レコードは仮想リストビューを埋めるために使用されます。OnData コードは次のとおりです。
procedure TForm1.ListViewData(Sender: TObject; Item: TListItem);
begin
Item.Caption := IntToStr(LURLs[Item.Index].Item);
Item.SubItems.Add(LURLs[Item.Index].SubItem1);
Item.SubItems.Add(LURLs[Item.Index].SubItem2);
end;
ユーザーがGOをクリックすると、アプリはワーカー スレッドの作成を制御する 1 つのスレッドを起動します。各ワーカー スレッドは URL を受け取り、それをダウンロードして解析し、詳細情報を取得します。
さて、ここに私の問題があります。少なくともタスク マネージャーによると、メモリ消費量は常に増え続けています。アプリを最小化して再度開くと、メモリ消費量は通常に戻りますが、仮想メモリの消費量は非常に高いままです。多くの人が、タスク マネージャーは信頼できないと言っています。しかし、しばらくすると、メモリの消費量が非常に多くなり、URL をダウンロードできなくなります。EOutOfMemoryエラーが発生します。私のコンピューターは非常に遅くなります。
FastMM4 によると、メモリ リークはありません。
ここで面白いことに、TVirtualList レコードを消去すると、「通常」と仮想の両方のメモリ消費量が通常に戻ります。でも、それをしない限り、それは非常に高いままです。アプリで何千もの URL をダウンロードできるようにしたいので、明らかにこれは問題です。しかし、このバグでは、あまり遠くまで行くことはできません。
TVirtualList レコードをクリアするコード
ListView.Items.BeginUpdate;
SetLength(LURLs,0);
ListView.Items.Count := Length(LURLs);
ListView.Clear;
ListView.Items.EndUpdate;
だから私はアプリを本質的に取り除いた. 解析は行われず、ファイルをダウンロードする代わりに、アプリはクリティカル セクションを使用して単一のローカル HMTL ファイルを読み込みます。メモリ消費の問題はまだ残っています。
制御スレッド:
unit Loader;
interface
uses Classes, SysUtils, Windows, Thread, Forms;
type
TLoader = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
procedure UpdateButtons;
procedure UpdateListView;
public
constructor Create;
end;
implementation
uses Main;
constructor TLoader.Create;
begin
inherited Create(False);
FreeOnTerminate := True;
end;
procedure TLoader.UpdateButtons;
begin
Form1.BSwitch(false); // Re-enable interface
end;
procedure TLoader.UpdateListView;
begin
Form1.ListView.Items.Item[BarP].MakeVisible(false); // Scroll down the listview
Application.ProcessMessages;
end;
procedure TLoader.Execute;
begin
while (BarP < Length(LURLs)) and (not(Terminated)) do // Is there any URL left?
begin
if (ThreadsR < StrToInt(Form1.Threads.Text)) then // Have we met the threads limit?
begin
Synchronize(UpdateListView);
TThreadWorker.Create(LURLs[BarP].SubItem1, BarP);
InterlockedIncrement(ThreadsR);
Inc(BarP);
end else Sleep(100);
end;
while (not(ThreadsR = 0)) do Sleep(100);
Synchronize(UpdateButtons);
end;
end.
ワーカー スレッド:
unit Thread;
interface
uses Classes, SysUtils, Windows, Forms;
type
TThreadWorker = class(TThread)
private
{ Private declarations }
Position : Integer;
HtmlSourceCode : TStringList;
StatusMessage, TURL : String;
procedure UpdateStatus;
procedure EndThread;
procedure AssignVariables;
procedure DownloadURL;
protected
procedure Execute; override;
public
constructor Create(URL : String ; LNumber : Integer);
end;
implementation
uses Main;
var CriticalSection: TRTLCriticalSection;
constructor TThreadWorker.Create(URL : String ; LNumber : Integer);
begin
inherited Create(False);
TURL := URL;
Position := LNumber;
FreeOnTerminate := True;
end;
procedure TThreadWorker.UpdateStatus;
begin
LURLs[Position].SubItem1 := StatusMessage;
Form1.ListView.UpdateItems(Position,Position);
end;
procedure TThreadWorker.EndThread;
begin
StatusMessage := 'Success';
Synchronize(UpdateStatus);
InterlockedIncrement(NDone);
// I free Synapse THTTPSend variable.
HtmlSourceCode.Free;
InterlockedDecrement(ThreadsR);
end;
procedure TThreadWorker.AssignVariables;
begin
StatusMessage := 'Working...';
Synchronize(UpdateStatus);
// I initialize Synapse THTTPsend variable.
HtmlSourceCode := TStringList.Create;
end;
procedure TThreadWorker.DownloadURL;
begin
(* This is where I download the URL with Synapse. The result file is then loaded
with HtmlSourceCode for further parsing. *)
EnterCriticalSection(CriticalSection);
HtmlSourceCode.LoadFromFile(ExtractFilePath(application.exename)+'testfile.html');
LeaveCriticalSection(CriticalSection);
Randomize;
Sleep(1000+Random(1500)); // Only for simulation
end;
procedure TThreadWorker.Execute;
begin
AssignVariables;
DownloadURL;
EndThread;
end;
initialization
InitializeCriticalSection(CriticalSection);
finalization
DeleteCriticalSection(CriticalSection);
end.