Abfangen von Speicherüberlauf

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
br_klaus
Beiträge: 244
Registriert: Do 21. Jan 2010, 22:33
OS, Lazarus, FPC: Windows Vista (L 0.9.31 FPC 2.5.1)
CPU-Target: 32Bit
Wohnort: z.z. Brasilien, sonst 82335 Berg-Leoni (südlich von München)

Abfangen von Speicherüberlauf

Beitrag von br_klaus »

Hallo,
habe wieder mal ein Problem.
Ich will einem Pointer einen großen Speicherbereich zuordnen mit getmem (etwa 500 MB, nämlich eine ganze Datei laden). Aber wenn der Speicher schon zu voll ist, dann gibt es da Access Violation. Wie läßt sich so etwas abfangen? (D.h. wie kann ich die maximal mögliche Speichergröße für die Zeigervariable feststellen?)
Leider gibt es ja nicht mehr die Funktion maxavail bzw memavail wie in Turbo Pascal, die einem sagte, wieviel Platz noch übrig bzw möglich ist.
Ginge das mit try .. except.. oder ähnlich? Könnte mir jemand einen Code dazu schreiben?
Herzlichen Dank.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2822
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Abfangen von Speicherüberlauf

Beitrag von m.fuchs »

Der mögliche Platz wäre auch schwer zu ermitteln und nützt dir nichts. Er kann ja zwischen Ermitteln und Reservieren bereits wieder belegt werden.

Aber zumindest den Fehler kannst du abfangen. Es gibt eine Varable namens ReturnNilIfGrowHeapFails. Wird diese auf True gesetzt (Standard ist False) dann gibt es keinen Fehler wenn der Speicher nicht ausreicht. Stattdessen wird einfach nil in den Pointer geschrieben. Und das kann man dann für seien Zwecke auswerten:

Code: Alles auswählen

var
  p: Pointer = nil;
begin
  ReturnNilIfGrowHeapFails := True;
  p := GetMem(500 * 1024 * 1024);
  if Assigned(p) then begin
    WriteLn('Ok');
    // (...)
  end else
    WriteLn('Nicht genug Speicher.');
end.
 
hth
Michael
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Abfangen von Speicherüberlauf

Beitrag von Socke »

br_klaus hat geschrieben:Ich will einem Pointer einen großen Speicherbereich zuordnen mit getmem (etwa 500 MB, nämlich eine ganze Datei laden). Aber wenn der Speicher schon zu voll ist, dann gibt es da Access Violation. Wie läßt sich so etwas abfangen?
Die Access Violation hat nichts mit der Speicherreservierung zu tun. Du solltest prüfen, ob du den Speicher erhalten hast. Wenn ja, ist definitiv genug Speicher da um die Datei zu laden (ACHTUNG: Datei mit Write-Lock vor getmem() öffnen!). Falls nicht, darfst du gar nicht erst mit dem Laden der Datei beginnen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2822
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Abfangen von Speicherüberlauf

Beitrag von m.fuchs »

Ahh, zu schnell gelesen. Ist es wirklich eine Access Violation oder ein RunError(204)? Nur letzterer würde auf den ungenügenden Speicher hinweisen.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Abfangen von Speicherüberlauf

Beitrag von Socke »

m.fuchs hat geschrieben:Ahh, zu schnell gelesen. Ist es wirklich eine Access Violation oder ein RunError(204)? Nur letzterer würde auf den ungenügenden Speicher hinweisen.
Bei Getmem() ist das RunError(203).
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2822
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Abfangen von Speicherüberlauf

Beitrag von m.fuchs »

Hm, ich gebe zu ich bin kein Experte für diesen Bereich.

Aber was ist dann hier passiert:

Bild

Setze ich ReturnNilIfGrowHeapFails auf True funktioniert es und ich bekomme p gefüllt mit nil zurück.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Abfangen von Speicherüberlauf

Beitrag von Socke »

Die Dokumentation zu den Run-Errors habe ich doch verlinkt. Da steht:
"204 Invalid pointer operation
This you will get if you call Dispose or Freemem with an invalid pointer (notably, Nil)"

Das heißt: du kannst in einer 32-Bit Anwendung keine 2^32 Byte anfordern.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2822
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Abfangen von Speicherüberlauf

Beitrag von m.fuchs »

Socke hat geschrieben:"204 Invalid pointer operation
This you will get if you call Dispose or Freemem with an invalid pointer (notably, Nil)"
Der Fehler kommt aber beim Aufruf von GetMem, deswegen bin ich jetzt etwas verwirrt. Aber vielleicht verstehe ich das alles nur falsch.
Socke hat geschrieben:Das heißt: du kannst in einer 32-Bit Anwendung keine 2^32 Byte anfordern.
Ja, das wäre doch aber laut Doku dann ein Fall für 203:
[...]However, if the heap has reached the maximum size allowed by the operating system or hardware, then you will get this error.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

br_klaus
Beiträge: 244
Registriert: Do 21. Jan 2010, 22:33
OS, Lazarus, FPC: Windows Vista (L 0.9.31 FPC 2.5.1)
CPU-Target: 32Bit
Wohnort: z.z. Brasilien, sonst 82335 Berg-Leoni (südlich von München)

Re: Abfangen von Speicherüberlauf

Beitrag von br_klaus »

Hallo, herzlichen Dank für die raschen Antworten. Werde es gleich mit dieser HeapVariablen ausprobieren.

Muß mich auch noch etwas korrigieren. Es sind natürlich keine 500 MB sondern "nur" 500 KB, und es wird auch keine Access Violation angezeigt, sondern es heißt da in der Fehlermeldung:
Projekt ... hat Exception-Klasse "External: SIGSEGV" ausgelöst, und dann folgt/folgen die Speicheradresse(n).
Aber da das genau dann pasierte, als ich der Zeigervariablen diese 500 K zuweisen wollte, dachte ich, muß es sich um eine Speicherverletzung handeln.

Socke hat geschrieben:Die Dokumentation zu den Run-Errors habe ich doch verlinkt. Da steht:
"204 Invalid pointer operation
This you will get if you call Dispose or Freemem with an invalid pointer (notably, Nil)"
Wo kann man denn diese Dokumentation zu den Run-Errors finden? Habe überall bei den Docs nachgeschaut, bin nicht fündig geworden...

Herzlichen Dank!

Michl
Beiträge: 2511
Registriert: Di 19. Jun 2012, 12:54

Re: Abfangen von Speicherüberlauf

Beitrag von Michl »

br_klaus hat geschrieben:Wo kann man denn diese Dokumentation zu den Run-Errors finden? Habe überall bei den Docs nachgeschaut, bin nicht fündig geworden...
Siehe verstecktem Link von Socke:
Socke hat geschrieben:Bei Getmem() ist das RunError(203).
Falls es noch jemanden interessiert? Der Runerror 204 scheint ein Grenzfall (bei Annäherung an maximale 32Bit-Größe) zu sein, nimmt man 100000Byte weniger, wird, so wie es sein soll, Runerror 203 ausgelöst.

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var
  p: Pointer = nil;
begin
//  ReturnNilIfGrowHeapFails := True;
  p := GetMem(4294967295);  //Runerror (204)
  p := GetMem(4294867295);  //Runerror (203)
  if Assigned(p) then Caption:='Ok'
                 else Caption:='Nicht genug Speicher.';
end; 

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection;  

br_klaus
Beiträge: 244
Registriert: Do 21. Jan 2010, 22:33
OS, Lazarus, FPC: Windows Vista (L 0.9.31 FPC 2.5.1)
CPU-Target: 32Bit
Wohnort: z.z. Brasilien, sonst 82335 Berg-Leoni (südlich von München)

Re: Abfangen von Speicherüberlauf

Beitrag von br_klaus »

Noch eine Frage zu den RuntimeErrors. Bei manchen gibt es doch die Möglchkeit, diese abzufangen durch bestimmte Kompilerschalter, zB bei Dateioperationen {$I-} Datei-Operation {$I+} und dann Abfrage einer bestimmten IO-result Variablen. Gibt es so etwas auch für andere Runtime Errors?
Herzlichen Dank.

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Abfangen von Speicherüberlauf

Beitrag von Socke »

br_klaus hat geschrieben:Muß mich auch noch etwas korrigieren. Es sind natürlich keine 500 MB sondern "nur" 500 KB, und es wird auch keine Access Violation angezeigt, sondern es heißt da in der Fehlermeldung:
Projekt ... hat Exception-Klasse "External: SIGSEGV" ausgelöst, und dann folgt/folgen die Speicheradresse(n).
Das ist beides das gleiche. Unter Windows wird das "Access Violation" genannt; unter Unix wird dem Prozess das Signal "Segmentation Fault" gesendet.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Antworten