Articles   Members Online: 3
-Article/Tip Search
-News Group Search over 21 Million news group articles.
-Delphi/Pascal
-CBuilder/C++
-C#Builder/C#
-JBuilder/Java
-Kylix
Member Area
-Home
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Login/Logout
-Become a Member
-Why sign up!
-Newsletter
-Chat Online!
-Indexes NEW!!
Employment
-Build your resume
-Find a job
-Post a job
-Resume Search
Contacts
-Contacts
-Feedbacks
-Link to us
-Privacy/Disclaimer
Embarcadero
Visit Embarcadero
Embarcadero Community
JEDI
Links
Delphi 3,4,5 TCollection Performance Issues and Solutions Turn on/off line numbers in source code. Switch to Orginial background IDE or DSP color Comment or reply to this aritlce/tip for discussion. Bookmark this article to my favorite article(s). Print this article
05-Nov-02
Category
VCL-General
Language
Delphi 3.x
Views
66
User Rating
No Votes
# Votes
0
Replies
0
Publisher:
DSP, Administrator
Reference URL:
DKB
			Author: Clever Components

Delphi 3,4,5 TCollection Performance Issues and Solutions

Answer:

If you are using TCollection classes in your Delphi 3,4 or 5 applications than you 
will find this article quite interesting.

Firstly let us try fairly simple code:

1   procedure TForm1.Button1Click(Sender: TObject);
2   var
3     old: TCollection;
4     i: integer;
5   begin
6     old := TCollection.Create(TCollectionItem);
7     for i := 0 to 100000 do
8     begin
9       old.Add;
10    end;
11    Windows.beep(900, 1000); // hi-freq beep after we done with adding empty items
12    old.Free;
13    Windows.beep(100, 1000); // low-freq beep after we done with destroying empty 
14  items
15  end;


You might think that low-freq beep will follow right after hi-freq beep (well what 
can be faster that just simply destroy all collection items) - but IT IS not!

In fact it takes 10-20 seconds to destroy collection which hold few dozen thousands 
items - and worse of all your CPU will be 100% busy. We bumped into this problem 
when our clients complains that application is "freeze PC for a few minutes".

To understand why it is happening you need take closer look at 
TCollectionItem.Destroy, TCollectionItem.SetCollection and TCollection.RemoveItem 
functions which located at classes.pas - last one is the key to understanding this 
problem.

You also might want to compare your TCollection.RemoveItem version to Delphi 6 
TCollection.RemoveItem code:

16  { classes.pas from Delphi 6 }
17  
18  procedure TCollection.RemoveItem(Item: TCollectionItem);
19  begin
20    Notify(Item, cnExtracting);
21    if Item = FItems.Last then
22      FItems.Delete(FItems.Count - 1) // that will fix original problem
23    else
24      FItems.Remove(Item);
25    Item.FCollection := nil;
26    NotifyDesigner(Self, Item, opRemove);
27    Changed;
28  end;


Now you probably will want to fix it. But seems it is not so easy because 
TCollection.RemoveItem is not a virtual or dynamic function.

Here is two solutions:

You will need to alter classes.pas - put that TCollection.RemoveItem code from 
Delphi 6 into your version of classes.pas.

Copy new (fixed) classes.pas into your project directory and put it at the first 
position in your .dpr uses section like this:

29  program Project1;
30  
31  uses
32    classes in 'classes.pas' // new classes.pas with fixed TCollection.RemoveItem
33    Forms,
34    Unit1 in 'Unit1.pas' {Form1};
35  
36  {$R *.res}
37  
38  begin
39    Application.Initialize;
40    Application.CreateForm(TForm1, Form1);
41    Application.Run;
42  end.
43  
44  //Now your project will be compiled with new version of TCollection.
45  
46  //In some situations it is not so convenient or even not possible to use altered 
47  classes.pas and in this case we have other trick for you.
48  
49  type
50    { TFixCollection - fix TCollection.RemoveItem issue in Delphi 3,4,5 }
51    TFixCollection = class(TCollection)
52    public
53      { Unfortunately Clear is not a virtual or dynamic procedure so we will 
54  		have to reintroduce it }
55      procedure Clear;
56      destructor Destroy; override;
57    end;
58  
59  procedure TFixCollection.Clear;
60  var
61    i: integer;
62    AList, OrgList: TList;
63  begin
64    AList := TList.Create;
65    try
66      OrgList := TList(PDWORD(DWORD(Self) + $4 + SizeOf(TPersistent))^);
67  
68      { Save original pointers to collection items }
69      for i := 0 to OrgList.Count - 1 do
70        AList.Add(OrgList[i]);
71  
72      OrgList.Clear;
73  
74      { Destroy collection items }
75      for i := 0 to AList.Count - 1 do
76        TCollectionItem(AList[i]).Free;
77    finally
78      AList.Free;
79    end;
80    inherited;
81  end;
82  
83  destructor TFixCollection.Destroy;
84  begin
85    Clear;
86    inherited;
87  end;
88  
89  { Let's try again ! }
90  
91  procedure TForm1.Button2Click(Sender: TObject);
92  var
93    old: TFixCollection;
94    i: integer;
95  begin
96    old := TFixCollection.Create(TCollectionItem);
97    for i := 0 to 100000 do
98      old.Add;
99    Windows.beep(900, 1000); // hi-freq beep after we done with adding empty items
100   old.Free;
101   Windows.beep(100, 1000); // low-freq beep after we done with destroying empty 
102 items
103 end;


As you can see now it works just fine. We used one trick which gives us access to 
protected section of TCollection.

You can use both techniques in your applications written on Delphi versions 3,4,5.

For your convenience you can download Delphi 3,4,5 TCollection performance issue demo sources here CollectionPerformanceDemo.zip

			
Vote: How useful do you find this Article/Tip?
Bad Excellent
1 2 3 4 5 6 7 8 9 10

 

Advertisement
Share this page
Advertisement
Download from Google

Copyright © Mendozi Enterprises LLC