Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Dynamische Arrays


Tobi482 - Di 15.01.08 19:47
Titel: Dynamische Arrays
Hi Leute,

mein Problem begegnet mir jetzt schon das zweite Mal in völlig verschiedenen Projekten. Es muss irgendwas mit dynamischen Arrays zu tun haben.

Am besten fange ich erstmal an zu erzählen^^

Ich habe ein Programm, das läuft wie ich es mir erhofft habe, ohne irgendwelche Fehler.

Nun habe ich dieses Programm um eine "Logging Funktion" erweitern. Es handlet sich dabei um einen separaten Thread der alle 10 Min Daten aus der Software ausliest und diese speichert.

Bei den Daten handelt es sich um Vektoren und Vermessungsdaten einer Messsonde. Je länger die Sonde läuft, desto mehr Messdaten kommen an.
Dabei liegt mein Interesse nicht an den Daten gemessen über der Zeit, sondern am gesamten Spektrum.

Ich frage also nicht ab Funktion(Zeitpunkt):Messwert, sondern Funktion(Messwert):Zeitpunkt.

Daher liest der Thread alle bereits gemessenen Daten ein und fügt immer nur dann Datensätze hinzu, wenn ein noch nicht gemessener Wert gemessen wurde.

Sobald ich den Thread starte kommt es nach einiger Zeit zu Fehlern.
Dabei handlet es sich meistens um Fehler wie "Stack überlauf" oder einfachste Funktionen AUßERHALB des Thread stürzen ab.

Wie kann eine Funktion, die immer problemlos funktionierte, Probleme verursachen nur weil ein Thread gestartet wurde?
z.B. diese hier, sie erzeugt irgendwelche Fehler (das Parameter String wird ja in wirklichkeit als Pointer übergeben. Dieser Pointer soll in einen ungülitigen Speicherbereich zeigen)

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
//Wandelt einen HexString in einen String um
Function HexStrToStr(Text:String):String;
var
     i         : Integer;
begin
     Result := '';

     While Length(Text) <> 0 do
     begin
          Result := Result + chr(StrToInt('$' + Text[1] + Text[2]));
          Delete(Text, 1, 3);
     end;
end;


Ich habe darauf hin angefangen den Thread zu untersuchen, irgendwas in ihm muss falsch sein. Ich habe den "bösen Teil" des Threads bereits gefunden, finde darin aber keine Fehler.

Plötzlich erinnerte ich mich an ein Problem, was mich vor einem halben Jahr dazu bewogen hat, ein Projekt abzubrechen, da ich mit meinem Latein am Ende war.

Es waren die gleichen unerklärlichen Fehler wie heute (Der Teufel steckt im Detail)

Wenn ich im Thread die Dynmaischen Arrays auskommentiere, läuft alles problemlos. Zum gleichen Schluss bin ich auch vor einem halben Jahr gekommen.

Entweder habe ich ein tief sitzendes Verständnisproblem mit diesen Arrays oder sie sind einfach verbugt wie früher die Streams auch.

Fragen:

Kann man dynamische Arrays in einen "packed record" einbinden?

Delphi-Quelltext
1:
2:
3:
4:
5:
Type
     TTRecord = packed record
          Datum        : TDateTime;
          Daten        : Array of TTDatensatz;
     end;

Sind dynmaische Arrays in einem Record über einen Record-Pointer ansprechbar?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
Type
     TTRecord = packed record
          Datum        : TDateTime;
          Daten        : Array of TTDatensatz;
     end;
     pTTRecord = ^TTRecord;

     //...

     SetLength(pTTRecord^.Daten, 10);
     High(pTTRecord^.Daten);
     pTTRecord^.Daten[i].Messwert := 0;

Können solche Record mit dynmaischen Arrays durch New und Dispose verwaltet werden?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
     var   pData : pTTRecord;

     New(pData);

     SetLength(pData^.Daten, 10);
     High(pData^.Daten);
     pData^.Daten[i].Messwert := 0;


Soblad auch nur wenigen Zeilen mit den dynmaischen Pointern benutzt wreden kommt es früher oder später zum crash.

Bin für jede Hilfe Dank und möchte mich schonmal im vorraus dafür bedanken.

Mit freundlichen Grüßen
Tobi


Xion - Mi 16.01.08 10:07

Hi,

Vermutung: TTDatensatz ist eine Klasse.

Wenn ja:
Du musst diese Klasse via FreeAndNil(Datensatz[x]) wieder wegräumen, falls du die Größe des Arrays veränderst, sonst gibts irgendwelche Speicherleichen (stack overflow).

Ansonsten:
von packed arrays hab ich keine Ahnung :nixweiss:

Xion


hazard999 - Mi 16.01.08 11:32

Hallo,

ich hatte mal vor längerer Zeit auch so ein Problem.

Bei mir hats daran gelegen wie Delphi strings verarbeitet im Zusammenhang mit dem MemoryManager der OutOfTheBox bei Delphi 6 dabei warst.

Wenn du deine HexStrToStr-Routine mit sehr großen Strings aufrufst, kann der Code zu einer fürchterlichen Speicherfragmentierung führen.

Die Auswirkungen können dann stark varieren (StackOverflow, OutOfMemoryExceptions...).

Folgender Vorschlag:

1. Funktionen verwenden die OutOfTheBox dabei sind (HexToBin)
2. StringListen statt strings verwenden (Besseres Speichermanagement)
3. Keine Löschung im string vornehmen, sondern immer nur die Zeichen rauskopieren die du brauchst


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
Function HexStrToStr(Text:String):String;
var
     i         : Integer;
begin
     Result := '';
     i := 1;

     While i <= Length(Text) do
     begin
          Result := Result + chr(StrToInt('$' + copy(Text, i, i + 2));
          i := i + 2;
     end;
end;


bzw


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
Function HexStrToStr(Text:String):String;
var
     i         : Integer;
     strl : TStringList;
begin
     strl : TStringList.create;
     Result := '';
     i := 1;

     While i <= Length(Text) do
     begin
          strl.Add(chr(StrToInt('$' + copy(Text, i, i + 2)));
          i := i + 2;
     end;
     result := stringReplace(strl.Text,#13#10,'',[rfReplaceAll, rfIgnoreCase]);
     strl.Free;
end;


r u

René


Tobi482 - Di 29.01.08 14:19

Hab ganz vergessen diesen Thread zu beenden
Danke nocheinmal für eure Hilfe

PS: Es waren echt sehr lange Strings^^ habe nun deinen Vorschlag benutzt und es funktioniert alles^^ DDANNKKEKE :)

Mit freundlichen Grüßen
Tobi