Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi NonVCL Version von Classes.dcu (https://www.delphipraxis.net/13413-nonvcl-version-von-classes-dcu.html)

Uncle Cracker 17. Dez 2003 21:50


NonVCL Version von Classes.dcu
 
Gibt es eine NonVCL für die unit Classes, denn brauche TString aus dieser Unit, doch leider wird die Datei von 8,5KB 114KB groß, wenn ich Classes einbinde.

Kann mir vielleicht jemand helfen?


:love: Danke UC

Luckie 17. Dez 2003 21:54

Re: NonVCL Version von Classes.dcu
 
TString? Ich kenne nur TStrings. Wenn du eine Stringliste brauchst, dass kan man sich einfach mit einem dynamsischen Array of String selber als Klasse nachprogrammieren.

Uncle Cracker 17. Dez 2003 21:58

Re: NonVCL Version von Classes.dcu
 
:love: Danke, werde das mal probieren.

PS: Ich meinte auch TStrings :roll:

Luckie 17. Dez 2003 22:02

Re: NonVCL Version von Classes.dcu
 
Auch eine schöne Fingerübung, um sich mal Klassen anzukucken. :zwinker:

Uncle Cracker 17. Dez 2003 22:12

Re: NonVCL Version von Classes.dcu
 
Ich bekomme das irgendwie nicht hin was zu ADDen :?

Ich wollte diese Funktion nur mal in NonVCL umsezten, doch leider bekomme ich nicht hin irgendwelche Daten in den Array.

Es soll mir jetzt keiner die Funktion in NonVCL machen, denn dann versteh ich es nicht, mir soll nur ein bisschen geholfen werden wie man das macht.


:love: Danke UC

toms 17. Dez 2003 22:55

Re: NonVCL Version von Classes.dcu
 
Vielleicht hilft dir das:

TStringList replacement by ~LOM~

Uncle Cracker 17. Dez 2003 23:04

Re: NonVCL Version von Classes.dcu
 
:love: Danke, ganau das habe ich gesucht. Ganz ohne Array ist immer noch besser :roll:


PS: Du musst in deiner Signatur noch was einfügen, denn nur die Countdownzahl sieht irgendwie komisch aus :zwinker:

Uncle Cracker 17. Dez 2003 23:26

Re: NonVCL Version von Classes.dcu
 
Ich hab' das nochmal probiert, dass auf die Funktion umzustellen, doch irgendwie klappt das nicht :?

Man kann zwar die Datei kompilieren, doch wenn ich die Datei starte kommt ein Anwendungsfehler, gibt es vielleicht noch eine andere Variante?

Luckie 18. Dez 2003 01:37

Re: NonVCL Version von Classes.dcu
 
Wo ist das Problem? Du nimmst dir ein dynamisches Array of String. Jedes mal, wenn du was hinzufügst (Methode Add) verlängerst du das Array um eins und fügst den String dort ein.
Delphi-Quellcode:
type TDynStringArray = array of Strings;
type
  TMyTringList = class
  private
    sl: TDynStringArray;
  public
    constructor Create;
    procedure Add;
  end;

constructor TMyStringlist.Create;
begin
  ...;
end;

procedure TMyStringList.Add(s: String);
var
  len: Integer;
begin
  len := length(sl);
  len := SetLength(sl, len+1);
  sl[len] := s;
end;
Nur mal so schnell ins Forum gehackt. Wenn es auch nicht kompiliert, sollte es zu mindest das Prinzip zeigen.

toms 18. Dez 2003 07:16

Re: NonVCL Version von Classes.dcu
 
Zitat:

Man kann zwar die Datei kompilieren, doch wenn ich die Datei starte kommt ein Anwendungsfehler,
Ich habe die Unit ausprobiert und es funktioniert bei mir ohne Probleme.

Zitat:

gibt es vielleicht noch eine andere Variante?
Hey, nicht so schnell aufgeben...Als Programmierer kannst du dir ja mal den Quellcode anschauen...

scp 18. Dez 2003 11:24

Re: NonVCL Version von Classes.dcu
 
Folgender Erweiterungsvorschlag für TStrList:

1. Die Funktion Strings in GetStr und Replace in SetStr umbenennen.
2. Die beiden Functionen in den protected Bereich verschieben.
3. Folgende Zeile ans Ende der public-Deklarition einfügen:

Delphi-Quellcode:
    property Strings[Index : Integer] : String read GetStr write SetStr; default;
Somit hat man mit ein bißchen Code ein Stück mehr das Verhalten von TStringList / TStrings.

OLLI_T 18. Dez 2003 13:19

Re: NonVCL Version von Classes.dcu
 
Da sind aber viele Fehler drin in dieser Klasse TStrList ... :gruebel:

scp 18. Dez 2003 13:57

Re: NonVCL Version von Classes.dcu
 
Zitat:

Zitat von OLLI_T
Da sind aber viele Fehler drin in dieser Klasse TStrList ... :gruebel:

Na, dann leg mal los. Ich hab sonst nix aussergewöhnliches gesehen. "Viele Fehler" ist ja nicht gerade eine hilfreiche Aussage.

Luckie 18. Dez 2003 14:00

Re: NonVCL Version von Classes.dcu
 
Zitat:

Zitat von scp
Zitat:

Zitat von OLLI_T
Da sind aber viele Fehler drin in dieser Klasse TStrList ... :gruebel:

Na, dann leg mal los. Ich hab sonst nix aussergewöhnliches gesehen. "Viele Fehler" ist ja nicht gerade eine hilfreiche Aussage.

Und bitte besser machen. :zwinker:

jbg 18. Dez 2003 16:48

Re: NonVCL Version von Classes.dcu
 
Zitat:

Zitat von Luckie
Jedes mal, wenn du was hinzufügst (Methode Add) verlängerst du das Array um eins und fügst den String dort ein.

Na dann viel Spaß mit dem sagenhaft geringen Speicherverbrauch von 200 MB für 5000 Elemente vom Typ Integer.

Luckie 18. Dez 2003 16:58

Re: NonVCL Version von Classes.dcu
 
War ja auch nur die einfache Version. Dass dies Speichertechnisch eigentlich Selbstmord ist, hätte ich noch erwähnen sollen. Aber in der hier geposteten Unit wird es nicht anders gemacht.

scp 18. Dez 2003 17:06

Re: NonVCL Version von Classes.dcu
 
Zitat:

Zitat von jbg
Zitat:

Zitat von Luckie
Jedes mal, wenn du was hinzufügst (Methode Add) verlängerst du das Array um eins und fügst den String dort ein.

Na dann viel Spaß mit dem sagenhaft geringen Speicherverbrauch von 200 MB für 5000 Elemente vom Typ Integer.

Ich weis zwar jetzt nich genau worauf du hinaus willst, aber die hier dargestellte TStrList unterscheidet sich kaum vom Original.
Auch bei der Borlandschen Version wird ein array verwendet, nur ist dies halt eine andere Art dynamisches Array:
Delphi-Quellcode:
  PStringItemList = ^TStringItemList;
  TStringItemList = array[0..MaxListSize] of TStringItem;
Es ist also zunächst eine statische Array, die aber nur den gerade nötigen Teil für die Anzahl Items per ReAllocMem() zugewiesen bekommt. Dies benötigt aber ebenfalls pro Element einen Integer-Wert (eigentlich ja Pointer), also 4 Byte + die Stringdaten.

PS: 5000 * 4 Byte sind doch 20000 Byte ~ 19,5 KB, oder wie meinst du das?

Chewie 18. Dez 2003 17:28

Re: NonVCL Version von Classes.dcu
 
Bei jedem Aufruf von SetLength wird das ganze Array an eine andere Speicherstelle verschoben, da nicht sicher ist, ob hinter der aktuellen Stelle noch genügend Platz dafür ist.
Durch irgendeine Schwäche im Delphi-Speichermanager (genaueres weiß ich auch nicht, würde mich auch mal interessieren) kann es nun passieren (und es passiert), dass der Speicher, den das Array vor dem Verschieben belegte, nicht wieder frei gegeben wird. Dadurch kommt die hohe Speicherbelastung zu Stande.
Daneben ist es natürlich auch höchst in effizient, wenn ständig Massen von Daten rumgeschoben werden, nur weil ein neuer String dazukommz.

jbg 18. Dez 2003 17:34

Re: NonVCL Version von Classes.dcu
 
Zitat:

Zitat von scp
aber die hier dargestellte TStrList unterscheidet sich kaum vom Original.

Aber das bisschen ist schon sehr ausschlaggebend.

Zitat:

Auch bei der Borlandschen Version wird ein array verwendet, nur ist dies halt eine andere Art dynamisches Array:
Das ist nicht das Problem.


Zitat:

5000 * 4 Byte sind doch 20000 Byte ~ 19,5 KB, oder wie meinst du das?
Theoretisch werden die 20000 Bytes auch nur reserviert. Praktisch wird Windows aber der Speicher in nicht geringen Mengen entzugen.


Zitat:

Es ist also zunächst eine statische Array, die aber nur den gerade nötigen Teil für die Anzahl Items per ReAllocMem() zugewiesen bekommt. Dies benötigt aber ebenfalls pro Element einen Integer-Wert (eigentlich ja Pointer), also 4 Byte + die Stringdaten.
Um es mal übertrieben darzustellen: Mit dieser Technik mishandelst du den Speichermanager von Delphi, der es dir dann mit einem Speicherbedraf gegen unendlich heimzahlt.

Bei jedem SetLength(a, Length(a) + 1) wird ein neuer Speicherbereich reserviert, die Daten kopiert und der alte als "Frei" vermerkt, also nicht an Windows zurückgegeben, da er später wieder benutzt werden könnte und somit schneller bereit steht, als wenn er erst bei Windows angefordert werden muss. Kommt nun die nächste Vergrößerung, so muss der Speichermanager wieder einen neuen Speicherbereich bei Windows reservieren, da das nun größere Array nicht in einen zuvor reservierten Speicher passt ...

Darum ist es besser, wenn man das Array einmalig auf die End-Länge setzt, anstatt jedesmal eins zur Länge hinzuzuaddieren. Man spart sich auch das ständige Kopieren des Arrays und gewinnt neben Speicherplatz auch an Geschwindigkeit.
Delphi-Quellcode:
var
  i: Integer;
  a: array of Integer;
begin
  ShowMessage('Start - Speicherschlucken');
  a := nil;
  for i := 0 to 99999 do
  begin
    SetLength(a, Length(a) + 1);
    a[i] := i;
  end;
  ShowMessage('Ende');
end;
Delphi-Quellcode:
var
  i: Integer;
  a: array of Integer;
begin
  ShowMessage('Start - Schneller und Speicherschonend');
  SetLength(a, 100000);
  for i := 0 to 99999 do
    a[i] := i;
  ShowMessage('Ende');
end;

scp 18. Dez 2003 17:35

Re: NonVCL Version von Classes.dcu
 
@chewie
Ersteres kann ich ja verstehen, wenn dem so ist, ist das natürlich ineffizient.

Aber das Massen von Daten verschoben werden, finde ich nicht so schlimm, es sind hier ja bei dem Bespiel mit den 5000 Elementen nur die 20 KB, was ja heutzutage nicht viel ist, die Daten der Strings bleiben ja unangetastet, weil es ja für jeden String einen Extra-Pointer/-Referenzzähler gibt.

scp 18. Dez 2003 17:39

Re: NonVCL Version von Classes.dcu
 
Zitat:

Zitat von jbg
Zitat:
Es ist also zunächst eine statische Array, die aber nur den gerade nötigen Teil für die Anzahl Items per ReAllocMem() zugewiesen bekommt. Dies benötigt aber ebenfalls pro Element einen Integer-Wert (eigentlich ja Pointer), also 4 Byte + die Stringdaten.

Um es mal übertrieben darzustellen: Mit dieser Technik mishandelst du den Speichermanager von Delphi, der es dir dann mit einem Speicherbedraf gegen unendlich heimzahlt.

Das war ja nicht meine Idee, sondern Borlands, die werden wohl ihren Speichermanager kennen?!?
Schau einfach mal in der Classes.pas, hast ja die D6Pro.

jbg 18. Dez 2003 17:40

Re: NonVCL Version von Classes.dcu
 
Zitat:

Zitat von Chewie
Durch irgendeine Schwäche im Delphi-Speichermanager

Das ist mehr eine Stärke des Delphi-Speichermanagers, die sich nur bei falscher Verwendung eben stark ins negative wendet.

Zitat:

kann es nun passieren (und es passiert), dass der Speicher, den das Array vor dem Verschieben belegte, nicht wieder frei gegeben wird.
Der Speicher wird schon freigegeben. Wobei er aber nicht an Windows-Speichermanager, sondern an den Delphi-Speichermanager geht, der sich die Adresse merkt um neue Anforderungen viel schneller zu verarbeiten als es der Windows Speichermanager kann.


Du kannst den folgenden Speichermanager, der nichts anderes macht als den Windows-Speichermanager aufzurufen, ja mal als Ersatz nehmen. (Erste Unit im Projektquellcode). Der Geschwindigkeitsunterschied bei vielen Komponenten auf den Formularen ist spürbar.

Delphi-Quellcode:
unit WinMemMan;
interface
uses Windows;

implementation
const
  HEAP_NO_SERIALIZE = 1;
  HEAP_ZERO_MEMORY = 8;

  HeapFlags: array[False..True] of Cardinal = (HEAP_NO_SERIALIZE, 0);

var
  ProcessHeap: THandle;

function HeapGetMem(Size: Integer): Pointer;
begin
  Result := HeapAlloc(ProcessHeap, HeapFlags[IsMultiThread], Size);
end;

function HeapFreeMem(P: Pointer): Integer;
begin
  if HeapFree(ProcessHeap, HeapFlags[IsMultiThread], P) then Result := 0 else Result := 1;
end;

function HeapReallocMem(P: Pointer; Size: Integer): Pointer;
begin
  Result := HeapReAlloc(ProcessHeap, HeapFlags[IsMultiThread], P, Cardinal(Size));
end;

procedure InitializeHeapMemManager;
var HeapMemManager: TMemoryManager;
begin
  ProcessHeap := GetProcessHeap;
  HeapMemManager.GetMem := HeapGetMem;
  HeapMemManager.FreeMem := HeapFreeMem;
  HeapMemManager.ReallocMem := HeapReallocMem;
  SetMemoryManager(HeapMemManager);
end;

initialization
  InitializeHeapMemManager;

end.

jbg 18. Dez 2003 17:42

Re: NonVCL Version von Classes.dcu
 
[quote="scp"]
Zitat:

Zitat von jbg
Das war ja nicht meine Idee, sondern Borlands, die werden wohl ihren Speichermanager kennen?!?

Genau. Borland kennen ihren Speichermanager und haben die Mishandlung auch umgangen.

Zitat:

Schau einfach mal in der Classes.pas, hast ja die D6Pro.
Das solltest du auch tun. Vielleicht fällt dir dann die Eigenschaft Capacity auf.

scp 18. Dez 2003 17:47

Re: NonVCL Version von Classes.dcu
 
Stimmt, die kenn ich zwar, hatte sie aber jetzt völlig ausser acht gelassen. Na dann eine andere Theorie:
Ist es nicht möglich, das bei einem dynamischen Array intern die gleiche vorgehensweise wie bei TStringList verwendet wird?

jbg 18. Dez 2003 17:51

Re: NonVCL Version von Classes.dcu
 
Natürlich. Schau dir einfach mal an, wie Borland das bei TStringList/TList mit Capacity gelöst hat. Einfach mal die gesamte Classes.pas nach Capacity durchsuchen. Dort wirst du auch eine schöne Formel finden, die sehr effektiv ist.

Da TStringList/TList noch aus Delphi 1 Zeiten stammen, wo dynamischen Arrays noch nicht vom Compiler unterstützt wurden, hat Borland einfach die "alte Art" der dynamischen Arrays benutzt.

scp 18. Dez 2003 17:58

Re: NonVCL Version von Classes.dcu
 
Ich selbst nutze sowieso mittlerweile die "alte Variante", da ich die Quelltexte auch auf D3 laufen haben will. Schliesslich kann sich das jetzt jeder leisten.
Aber interessant mal die doch gravierenden Unterschiede kennenzulernen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:19 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz