Array lockere Bereichs- (Range-) check

Für Fragen rund um die Ide und zum Debugger

Re: Array lockere Bereichs- (Range-) check

Beitragvon Warf » 27. Jul 2018, 22:41 Re: Array lockere Bereichs- (Range-) check

af0815 hat geschrieben:Ein klares nein. Nur weil ein Compiler nicht meckert ist der Code nicht in Ordnung. Wenn der Compiler nicht meckert heisst das nur das die Syntax stimmt - mehr nicht. Ob der Code korrekt ist, kann er nicht feststellen. Vor allen wenn man in Richtung Pointer oder Casts geht, kann der Compiler nicht alles prüfen.

Es ging grade um das CODE segment im speicher, welche größe das hat. Und das sollte man komplett dem Compiler überlassen, denn als programmierer hat man darauf nur geringen einfluss (Man kann versuchen per hand den assembly zu optimieren, aber ob sich das wirklich lohnt sei mal dahingestellt)

af0815 hat geschrieben:Auch die größe der Datentypen sind nicht in Stein gemeisselt. Es gibt Typen die haben immer die gleiche Größe, andere könne je nach Plattform sich ändern.

So sind die Aussagen zu einfach gehalten.


Das stimmt natürlich gibt es diverse Plattformabbhängige typen, richtig wäre alle Grunddatentypen (und damit auch kombinationstypen wie arrays und records) haben die selbe größe
Warf
 
Beiträge: 1136
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon Erwin » 28. Jul 2018, 09:45 Re: Array lockere Bereichs- (Range-) check

Das hört sich ja alles so an, als würde es nichts bringen, die Formel für den Speicherbereich etc. herauszufinden, bzw. das Ganze auszurechnen?
Irgendwie ernüchtern und erschreckend, dass es da keine klare Aufteilung oder dergleichen gibt. Dachte eigentlich immer, dass so lange es nur xx-RAM nutzt, dies dann überall gleich ist, und auch sonst nichts passieren kann?
Aber das würde erklären, wieso in der Vergangenheit paar Spiele auf meinen Rechner nicht liefen.
Win 7 / Lazarus 1.6 / FP 3.0.0 / x86_64-win64-win32/win64
Erwin
 
Beiträge: 223
Registriert: 16. Sep 2009, 13:15
OS, Lazarus, FPC: Xubuntu 16.04 / x86_64_linux-gtk 2 / L 1.6+dfsg-1 / FPC 3.0.0 | 
Nach oben

Beitragvon kupferstecher » 28. Jul 2018, 11:04 Re: Array lockere Bereichs- (Range-) check

Erwin hat geschrieben:Das hört sich ja alles so an, als würde es nichts bringen, die Formel für den Speicherbereich etc. herauszufinden, bzw. das Ganze auszurechnen?

Auszurechnen sowieso nicht.
Man muss halt wissen, dass man den Stack nicht überstrapazieren sollte. Das heißt große statische Arrays sollten nicht lokal in Funktionen angelegt werden (sondern als globale Variablen oder als dynamisches Array). Dynamische Arrays werden auf dem Heap angelegt, ist also problemlos. Außerdem liegen lokale Shortstrings auf dem Stack, aber bei der PC-Programmierung verwendet man die ja sowieso nicht. Auf sonstige lokale Variablen wie Integer, Float usw. braucht man auf einem PC nicht zu achten, so viel kann man gar nicht tippen um den Stack zu gefährden. D.h. für das tägliche Programmieren hat das keine Relevanz.
kupferstecher
 
Beiträge: 217
Registriert: 17. Nov 2016, 11:52

Beitragvon Mathias » 28. Jul 2018, 16:11 Re: Array lockere Bereichs- (Range-) check

Außerdem liegen lokale Shortstrings auf dem Stack, aber bei der PC-Programmierung verwendet man die ja sowieso nicht.

Das stimmt nicht, auch auf dem PC werden ShortString gebraucht.

ZB wen man eine alte Datei einlesen will. Oder wie willst du folgendes lösen ?

Code: Alles auswählen
type
  TData = record
    i: Int16;
    s: string[10];
  end;
var
  Data: TData;
  f: file of TData;
begin
  AssignFile(f, 'test.dat');
  Reset(f);
  Read(f, Data);
  CloseFile(f);
...
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4344
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Warf » 28. Jul 2018, 16:31 Re: Array lockere Bereichs- (Range-) check

Mathias hat geschrieben:Das stimmt nicht, auch auf dem PC werden ShortString gebraucht.

ZB wen man eine alte Datei einlesen will. Oder wie willst du folgendes lösen ?


Nicht nur alte dateien, ich verwende bis heute oft ShortStrings für binäre dateien zu schreiben, da ich sie das lesen und schreiben von Dateien extrem vereinfachen. Solang man garantieren kann das diese sich in einer gewissen größenordnung aufhalten. Name, Postleitzahlen, Addressen, Hausnummern, all das passt problemlos in shortstrings und das macht das speichern und laden extrem viel einfacher.

Selbes gilt natürlich auch für shared memory und sockets. Ich kann einen shortstring einfach direkt in einen TCP stream schreiben, und ihn auf meinem server lesen, mit nur 1 zeile code auf jeder seite
Warf
 
Beiträge: 1136
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon Mathias » 28. Jul 2018, 16:44 Re: Array lockere Bereichs- (Range-) check

Nicht nur alte dateien, ich verwende bis heute oft ShortStrings für binäre dateien zu schreiben, da ich sie das lesen und schreiben von Dateien extrem vereinfachen.
Für etwas neues würde ich sowieso FileStream verwenden. Aber es stimmt, mit ShortString ist es sehr einfach, dafür verschwendet es Platz.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4344
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Warf » 28. Jul 2018, 17:24 Re: Array lockere Bereichs- (Range-) check

Mathias hat geschrieben:Für etwas neues würde ich sowieso FileStream verwenden. Aber es stimmt, mit ShortString ist es sehr einfach, dafür verschwendet es Platz.


Ja aber man kann ja auch records mit shortstrings in Streams schreiben:
Code: Alles auswählen
Fs.Write(MyData, SizeOf(MyData))


Und die Platzverschwendung ist ja auch nicht so das sonderlich große Problem, da ein shortstring maximal 256 Zeichen lang werden kann, muss man schon ne menge daten haben damit das zum problem wird.
Im vergleich dazu, TLists verwenden geometrische Kapazitäten, das bedeutet wenn du ein element hinzufügst, das über die kapazität ausreicht, wird die kapazität um einen Faktor C vergrößert. Im worst case verwendet eine TList also C mal so viel speicher wie notwendig (ich glaube früher war C = 2, heute skaliert das je nach größe, also bei kleinen listen 2, bei großen listen 1,irgendwas). Wenn du deine Shortstrings in einer Liste organisierst kann es also gut sein das du durch die liste mehr platz verlierst als durch die Shortstrings
Warf
 
Beiträge: 1136
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon Mathias » 28. Jul 2018, 17:31 Re: Array lockere Bereichs- (Range-) check

Ja aber man kann ja auch records mit shortstrings in Streams schreiben:

Wieso sollte dies nicht gehen, ein ShortString ist nichts anderes als eine statische Array.

Im vergleich dazu, TLists verwenden geometrische Kapazitäten, das bedeutet wenn du ein element hinzufügst, das über die kapazität ausreicht, wird ...

Muss man bei TList nicht den Speicher selber reservieren ?
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4344
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Warf » 28. Jul 2018, 18:01 Re: Array lockere Bereichs- (Range-) check

Mathias hat geschrieben:Wieso sollte dies nicht gehen, ein ShortString ist nichts anderes als eine statische Array.


Ja aber ich meine das ist immernoch einfacher als einen Record der z.B. einen Dynamischen string enthält reinzuschreiben, da man dann jedes feld per hand reinschreiben muss.

Muss man bei TList nicht den Speicher selber reservieren ?

Mit dem TList.Create erstellt man nur sozusagen das Kontrollobjekt, mit einem gewissen grundspeicher für die ersten paar elemente (keine ahnung wie viel, irgendwas zwischen 2-16 elemente oder so). Der speicher für die elemente wird dann beim add bzw remove von elementen angepasst (also wenn nach einem remove zu viel speicher frei ist, wird der verkleinert, wenn ein add mehr speicher verbraucht als aktuell vorhanden ist wird faktoriell vergrößert).

Die Idee dahinter ist, das speicher vergrößern und verkleinern echt langsam ist, und damit viele adds/removes nicht ewig viel Zeit brauchen wird also der speicher überapproximiert
Warf
 
Beiträge: 1136
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon Mathias » 28. Jul 2018, 19:13 Re: Array lockere Bereichs- (Range-) check

Ja aber ich meine das ist immernoch einfacher als einen Record der z.B. einen Dynamischen string enthält reinzuschreiben, da man dann jedes feld per hand reinschreiben muss.
Das stimmt, bei dynamischen Sachen muss man immer zuerst die Länge schreiben.

Mit dem TList.Create erstellt man nur sozusagen das Kontrollobjekt, mit einem gewissen grundspeicher für die ersten paar elemente (keine ahnung wie viel, irgendwas zwischen 2-16 elemente oder so). Der speicher für die elemente wird dann beim add bzw remove von elementen angepasst (also wenn nach einem remove zu viel speicher frei ist, wird der verkleinert, wenn ein add mehr speicher verbraucht als aktuell vorhanden ist wird faktoriell vergrößert).
Im Prinzip könnte man die auch selbst mit einer verketteten Liste machen. Aber dies ist mehr Aufwand.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4344
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Warf » 28. Jul 2018, 19:38 Re: Array lockere Bereichs- (Range-) check

Mathias hat geschrieben:Im Prinzip könnte man die auch selbst mit einer verketteten Liste machen. Aber dies ist mehr Aufwand.


Ja wobei ArrayListen (wie es TList ist) andere Vorteile haben, z.B. sind diese Cachebar, das heißt sukzessive zugriffe auf elemente die nah beieinander leiegen brauchen da viel weniger zeit als das auflösen der Verketteten liste. In Java verwendet die LinkedList daher verkette blöcke von arrays, das aber selbst zu bauen ist mir definitiv zu viel aufwand. Ein Nachteil der ArrayLists ist allerdings, wenn der Heap fragmentiert ist und die Liste sehr groß, kann es sein das sie nicht vergrößert werden kann, obwohl es eigentlich genug freien speicher gäb, weil es einfach keinen großen zusammenhängenden block mehr gibt sondern nur viele kleine.

Ich verwende aktuell am liebsten die generischen TFPGList und TFPGObjectList klassen. Die machen einem das leben echt einfach
Warf
 
Beiträge: 1136
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon Mathias » 28. Jul 2018, 20:07 Re: Array lockere Bereichs- (Range-) check

Ein Nachteil der ArrayLists ist allerdings, wenn der Heap fragmentiert ist und die Liste sehr groß, kann es sein das sie nicht vergrößert werden kann, obwohl es eigentlich genug freien speicher gäb, weil es einfach keinen großen zusammenhängenden block mehr gibt sondern nur viele kleine.
Ich habe mal bei einer Dynamischen Array die Länge immer um 1 erhöht, so wie ich mich erinnern mag ging es sehr lange, bis ich an irgend ein Limit stoss.

Ich lasse gerade folgende Code laufen, das geht ja ewig, bis da ein Fehler kommt.
Jetzt bin ich schon auf 1,6GByte. Mein PC hat 16GByte RAM.

Code: Alles auswählen
 
type
  TMil = array[0..1000000] of byte;
var
  i: integer;
  a: array of TMil;
begin
  repeat
    SetLength(a, Length(a) + 1);
    WriteLn(Length(a));
  until 1 = 2;
end
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4344
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Warf » 28. Jul 2018, 20:20 Re: Array lockere Bereichs- (Range-) check

Mathias hat geschrieben:Ich habe mal bei einer Dynamischen Array die Länge immer um 1 erhöht, so wie ich mich erinnern mag ging es sehr lange, bis ich an irgend ein Limit stoss.

Ich lasse gerade folgende Code laufen, das geht ja ewig, bis da ein Fehler kommt.
Jetzt bin ich schon auf 1,6GByte. Mein PC hat 16GByte RAM.

Code: Alles auswählen
 
type
  TMil = array[0..1000000] of byte;
var
  i: integer;
  a: array of TMil;
begin
  repeat
    SetLength(a, Length(a) + 1);
    WriteLn(Length(a));
  until 1 = 2;
end

Wenn du linux verwendest kommen noch ein paar gb swap dazu, da kannst du ne ganze weile warten. Um an das fragmentierungsproblem zu stoßen müsstest du aber noch viel mehr dynamische Speicherzellen erstellen und dann zum teil wieder freigeben. Z.B. könntest du eine reihe an zeigern dir mit getmem besorgen (zufällige größe), dann zufällig welche davon wieder löschen, und dann das ganze mit einer TList versuchen (die wächst schneller). Wenn du das mit genug objekten machst solltest du recht schnell an die fragmentierungsprobleme stoßen (normalerweise treten die halt auf wenn eine software bereits schon lange läuft und sehr oft neue objekte erstellt und gelöscht hat)
Warf
 
Beiträge: 1136
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon Mathias » 28. Jul 2018, 20:30 Re: Array lockere Bereichs- (Range-) check

Es ist gar nicht so einfach den Speicher voll zu kriegen, Swap wurde immer noch nicht angegriffen.. :mrgreen:
Einzig, die Schleife wird langsamer.
Code: Alles auswählen
top - 21:29:38 up  1:20,  1 user,  load average: 1.12, 1.18, 1.09
Tasks: 250 gesamt,   2 laufend, 175 schlafend,   0 gestoppt,   0 Zombie
%CPU(s):  5.7 be,  7.6 sy,  0.0 ni, 86.5 un,  0.2 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Spch : 16120824 gesamt,  8813876 frei,  5337316 belegt,  1969632 Puff/Cache
KiB Swap: 16735228 gesamt, 16735228 frei,        0 belegt.  9982556 verfü Spch
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4344
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon af0815 » 29. Jul 2018, 10:22 Re: Array lockere Bereichs- (Range-) check

Ich verwende folgendes für Tests

Code: Alles auswählen
procedure TForm1.BuTestitClick(Sender: TObject);
const
  coTestsize = 10*1024*1024;
  coKB = 1024;
  coMB = coKB * 1024;
var
  list : TList;
  i,j,aktIDX : Integer;
begin
  list := TList.Create;
  //
  for i := 1 to 10000 do begin
    if i mod 5 = 0 then Memo1.Append('Used size: ' + IntToStr((i*coTestsize) div (coMB))+ ' MB');
    aktIDX := list.Add(getmem(coTestsize)); // List of PChar
    if list.Items[aktIDX] = pointer(0) then begin
      Memo1.Append('No memory at : ' + IntToStr(i));
      exit;
    end;
    for j := 0 to coTestsize-1 do begin
      PChar(list.Items[aktIDX])[j] := #$FA;
    end;
  end;
  list.Free;
end;

Bei win32 ist ohne PE Flag bei 1.7 GB Schluss, mit PE-Flag ca. 3.7 GB
Bei win64 ist bei mir bei ca. 90GB Schluss Win10/64/Pro. Bei 24GB Basisram. Dabei sieht man, das Windows scheinbar den Speicher beim swappen komprimiert, da der Zuwachs im Swap nur marginal ist.

Ev. mal für Linux testen :-) dann habe hat man Vergleichswerte für Linux auch.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).
af0815
 
Beiträge: 3695
Registriert: 7. Jan 2007, 10:20
Wohnort: Niederösterreich
OS, Lazarus, FPC: FPC 3.2 Lazarus 2.0 per fpcupdeluxe | 
CPU-Target: 32Bit (64Bit)
Nach oben

» Weitere Beiträge siehe nächste Seite »
VorherigeNächste

Zurück zu Benutzung der IDE



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste

porpoises-institution
accuracy-worried