Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   SetLength / Getmem / AllocMem out of memory Problem (https://www.delphipraxis.net/141351-setlength-getmem-allocmem-out-memory-problem.html)

greenmile 7. Okt 2009 16:31


SetLength / Getmem / AllocMem out of memory Problem
 
Hallo,

in meinem Rechner sind, laut Taskmanager, rund 2 GByte verfügbarer Speicher frei . Wenn ich nun ein "Array of Byte" mittels SetLength, oder GetMem, oder AllocMem auf einen Wert > 800 MB setze, bekomme ich ein "EOutOfRessource" Problem, es funktioniert nur bis zu 750 MByte. Gibt es da eine Einschränkung von Delphi? Speicher ist ja da, aber irgendwie finde ich die Logik nicht, wieso es nicht funktioniert ... Hilfe ...

Bernhard Geyer 7. Okt 2009 16:36

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Zitat:

Zitat von greenmile
Gibt es da eine Einschränkung von Delphi?

Nö, aber von Windows. Du forderst den Speicher (zwangsweise bei einem Array) als durchgängigen Adressraum an. Und da alle möglichen DLL's kreuz und quer in deinem 4GB (bzw. 2GB User-)Adressraum geladen werden solltest du froh sein überhaupt 750 MB an einem Stück anfordern zu können.

himitsu 7. Okt 2009 16:43

Re: SetLength / Getmem / AllocMem out of memory Problem
 
bei 4 GB ist die Chance groß, daß alles nur in den ersten 2 GB liegt und man somit auch mal mehr zusammenhängenden Speicher bekommt.

Es gibt da nur noch eine Möglichkeit um einen größeren "zusammenhängenden" Speicher auch bei wenig freiem "Platz" hinzubekommen

MMF (Memory Mappes Files) geht auch ohne Dateien, dabei reserviert man sich z.B. genügend Speicher bei Windows und mappt dann nur den gerade benötigten Teil in seinen Anwendunsspeicher.


Ansonsten bleibt dier nur die Wahl einer anderen Speichermethode
z.B. verkettete Liste statt Array
oder eine Gruppe aus mehreren kleineren Arrays


PS: Du kannst dir gern mit der Demo von dort mal deinen Speicher einiger Anwendungen anzeigen
http://www.delphipraxis.net/internal...ct.php?t=62381
allerdings sind dort nur die gemappten Dateien angezeigt und es ist zwischendurch natürlich noch jede Menge anderer Speicher belegt, aber man sieht schonmal deutlich, daß es schwer ist da einen großen zusammenhängenden Speicher zu bekommen.

Luckie 7. Okt 2009 20:40

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Zitat:

Zitat von himitsu
bei 4 GB ist die Chance groß, daß alles nur in den ersten 2 GB liegt und man somit auch mal mehr zusammenhängenden Speicher bekommt.

Was? Effektiv hat man 2 GB Adressraunm zur Verfügung. Was meinst du jetzt mit deiner Aussage?

himitsu 7. Okt 2009 21:04

Re: SetLength / Getmem / AllocMem out of memory Problem
 
man kann es doch auf 3,irgendwas GB erweitern (unter bestimmten Vorausetzungen)

Luckie 7. Okt 2009 21:28

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Kann man, in der Boot.ini. Ist aber nicht zu empfehlen, weil schon 2GB für Windows ziemlich knapp bemessen sind. Aber davon mal abgesehen, ich hatte bisher noch nie den Fall, dass mir bei meinen Programmen der Speicher ausgegangen ist. Man sollte also noch mal das Konzept überdenken. Eventuell mit die Datei nur stückweise in den Speicher laden mit MemoryMappedFiles.

Bernhard Geyer 7. Okt 2009 21:36

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Zitat:

Zitat von himitsu
man kann es doch auf 3,irgendwas GB erweitern (unter bestimmten Vorausetzungen)

Nur wenn die Exe auch entsprechend Kompiliert wure. Aber seit Windows 2003/Vista/2008/7 würde ich statt ein 32-Bit OS mit einer Bootoption instabil zu machen gleich die 64-Bit Version nehmen.

Zitat:

Zitat von Luckie
Aber davon mal abgesehen, ich hatte bisher noch nie den Fall, dass mir bei meinen Programmen der Speicher ausgegangen ist.

Wir hatten wir schon den Fall das wir als Hotfix den 3GB-Option beim Compiliern mit D6 aktivieren mussten. Das nächste "normale" Maintenance-Release hatte den Implementierungsfehler behoben und unser App hat sich dann wieder mit << 1 GB RAM bei der Verarbeitung einer größeren DB-Menge begnügt.

himitsu 7. Okt 2009 22:22

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Zitat:

Zitat von Bernhard Geyer
Nur wenn die Exe auch entsprechend Kompiliert wure.

joar, jetzt fehlt nur noch das passende 64-Bit-Delphi, damit man auch richtig für das Win64 schreiben kann :?

greenmile 8. Okt 2009 08:42

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Vielen Dank für die Antworten/ausführlichen Ausführungen. Ich benötige im Prinzip nur x MByte/GByte, die ich ansprechen kann. Woher die kommen ist mir dabei egal :) Also bräuchte ich im Prinzip ein (Array of [Array .. MByte])?

"z.B. verkettete Liste statt Array"

Was meinst Du genau damit?

Bernhard Geyer 8. Okt 2009 08:49

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Zitat:

Zitat von greenmile
Vielen Dank für die Antworten/ausführlichen Ausführungen. Ich benötige im Prinzip nur x MByte/GByte, die ich ansprechen kann. Woher die kommen ist mir dabei egal :) Also bräuchte ich im Prinzip ein (Array of [Array .. MByte])?

Wie schon gesagt. Geht nicht mit Array of Byte.
Dur wirst hier auf andere Datenstrukturen wie verkettete Listen oder ähnliches wechseln müssen.

greenmile 8. Okt 2009 08:51

Re: SetLength / Getmem / AllocMem out of memory Problem
 
"z.B. verkettete Liste statt Array"

Was meinst Du genau damit?

hoika 8. Okt 2009 09:30

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Hallo,

kennst du keine verketteten Listen ? tztz ;)

Jedes Listen-Element ist ein Record oder eine Klasse,
wobei jedes Element seinen Nachfolger kennt.
Das letzte Element hat NIL als Nachfolger.
Kennt ein Elment auch seinen Vorgänger,
sprucht man von doppelt verketteten Listen.

Hier wird dann der Speicher immer häppchenweise
und nicht am Stück angefordert.




Heiko

greenmile 8. Okt 2009 09:33

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Hört sich gut an, hast Du ein Beispiel für mich?

Zitat:

Zitat von hoika
Hallo,

kennst du keine verketteten Listen ? tztz ;)

Jedes Listen-Element ist ein Record oder eine Klasse,
wobei jedes Element seinen Nachfolger kennt.
Das letzte Element hat NIL als Nachfolger.
Kennt ein Elment auch seinen Vorgänger,
sprucht man von doppelt verketteten Listen.

Hier wird dann der Speicher immer häppchenweise
und nicht am Stück angefordert.




Heiko


himitsu 8. Okt 2009 09:36

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Bei Google suchenverkettete Liste

das ganze nochmal kurz als Array ... zum Vergleich
Delphi-Quellcode:
TData = record
  name: String;
  typ: Integer;
  ...
end;

TAsArray = Array of TData;
eine einfach verkettete Liste
Delphi-Quellcode:
PListe = ^TListe;
TListe = record
  next: PListe;

  name: String;
  typ: Integer;
end;

var myList: PListe;
bei dieser verketten Liste ist es so, daß nur der Zeiger auf das erste Element in der Liste bekannt ist
und jede Element kennt dann seinen Nachfolger ... du kannst dich also vom ersten element aus zu allen anderen Elementen durchhangeln


und das wäre dann eine doppelt verkettete Liste
Delphi-Quellcode:
PListe = ^TListe;
TListe = record
  prev: PListe;
  next: PListe;

  name: String;
  typ: Integer;
end;

var myList_first: PListe;
    myList_last: PListe;
hier kennt dann jedes Element auch noch seinen Vorgänger ... das macht es dann einfacher diese Liste zu "editieren" (zu verändern, wie z.B. Einträge einzufügen oder zu entfernen)


Der Vorteil gegenüber dem Array ist dann einfach, daß diese Daten nicht stur alle in einer Reihe angeordnet sein müssen ... sie können sich also frei im verfügbaren Speicher verteilen und brauchen keinen gemeinsamen Speicherblock.


Was jetzt aber für dich eine "gute" Lösung wäre, das kommt darauf an, wie der Zugriff auf deine Daten aussieht, wie/ob diese auch mal verändert werden und vorallem welche und wieviele Daten du in jedem Element drinnen hast.

z.B. bei einem Array of String wäre es Schwachsinn dieses als verkettete Liste verwalten zu wollen, da so der Speicherverbrauch und auch der Verwaltungsaufwand wesentlich höher wäre, als beim Array.

greenmile 8. Okt 2009 10:33

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Danke für die Beispiele. Aber bei 800 MByte sorgt das ja ordentlich für Overhead.

himitsu 8. Okt 2009 10:37

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Drum sagte ich ja, es gibt mehrere Möglichkeiten, welche man dann entsprechend abwegen kann.

eine Möglichkeit wäre z.B. auch das Array einfach aufzuteilen

Delphi-Quellcode:
// statt
TMyArray = Array of Data;

// dieses
TMyArray = Array of Array of Data;
Das SetLength ist dann zwar ein bissl umständlich zu erledigen, aber zugreifen könnte man dann z.B. so
(wenn man davon ausgeht, daß nach jeweils 1000 Einträgen ein neues SubArray erstellt wurde)
Delphi-Quellcode:
MyArr[i]

MyArr[i div 1000, i mod 1000]
[add]
Length würde dann etwa so aussehn
Delphi-Quellcode:
// für's normale Array
Length(MyArr)

// eine kleine Funktion für das gesplittete Array
function MyLength(var MyArr: ...): Integer;
begin
  Result := High(MyArr) * 1000 + Length(MyArr[High(MyArr)]);
end;

greenmile 8. Okt 2009 10:55

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Es geht um ein Array of Byte. Die externe Funktion ruft ein OnRead / OnWrite Callback auf. Im "OnRead" wird übergeben, ab welcher Position wieviel Bytes gelesen und in einen Buffer geschrieben werden. Bei "OnWrite" wird übergeben, wieviel Bytes an welcher Position in den lokalen Puffer geschrieben werden.

Übergeben wird dann zum Beispiel 4096 Bytes an Position X (z.B. 600 MByte). Momentan erledige ich das mit einem Array of Byte, weil da Position 4096 ja bekannt ist (mittels Move(MyArrayOfByte[ReadOffset],ReadBuffer,ReadSize)). Wenn ich das alles aber aufsplitte, dann ist u.U. genau bei 4000 schluß und ich muss die restlichen 96 Bytes woanders lesen.

himitsu 8. Okt 2009 11:06

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Die über 800 MB dann so im RAM behalten zu wollen ist dann aber wohl eher ein Designfehler in der Anwendung.

Hier würde sich dann eine MMF anbieten ... diese in der entsprechenden Größe erstellt

dann einfach nur den Bereich z.B. 4096 Bytes ab Position sound so in den Speicher mappen, die Daten da reinkopieren und dann den Bereich eventuell gleich wieder freigeben.


für alle möglichen anderen Fälle ginge z.B. sowas (also ab Delphi 2006)
dieses stellt quasi ein einfaches dynamisches Array mit gesplittetem Datenbereich dar
Delphi-Quellcode:
Type TSplittArray<Typ> = Record
  Private
    Var _SplittSize: Integer;
      _Data: Array of Array of Typ;
    Function Getter(Index: Integer):            Typ; Inline;
    Procedure Setter(Index: Integer; Const Value: Typ); Inline;
  Public
    Procedure SetSplittSize(i: Integer);
    Procedure SetLength   (i: Integer);
    Function Length:         Integer; Inline;
    Function High:           Integer; Inline;
    Property Value[Index: Integer]: Typ Read Getter Write Setter; Default;

    //Procedure Push(Const Value: Typ);
    //Function Pop: Typ;
  End;

Function TSplittArray<Typ>.Getter(Index: Integer): Typ;
  Begin
    Result := _Data[Index div _SplittSize, Index mod _SplittSize];
  End;

Procedure TSplittArray<Typ>.Setter(Index: Integer; Const Value: Typ);
  Begin
    _Data[Index div _SplittSize, Index mod _SplittSize] := Value;
  End;

Procedure TSplittArray<Typ>.SetSplittSize(i: Integer);
  Begin
    If Assigned(_Data) Then System.Error(reInvalidOp);
    _SplittSize := i;
  End;

Procedure TSplittArray<Typ>.SetLength(i: Integer);
  Var i2: Integer;

  Begin
    i2 := System.High(_Data);
    System.SetLength(_Data, (i - 1) div _SplittSize + 1);
    For i2 := i2 to System.High(_Data) - 1 do
      System.SetLength(_Data[i2], _SplittSize);
    If i > 0 Then
      System.SetLength(_Data[System.High(_Data)], i mod _SplittSize);
  End;

Function TSplittArray<Typ>.Length: Integer;
  Var i: Integer;

  Begin
    i := System.High(_Data);
    Result := i * 1000 + System.Length(_Data[i]);
  End;

Function TSplittArray<Typ>.High: Integer;
  Begin
    Result := Length - 1;
  End;

{Procedure TSplittArray<Typ>.Push(Const Value: Typ);
  Var i: Integer;

  Begin
    i := Length;
    SetLength(i + 1);
    Setter(i - 1, Value);
  End;

Function TSplittArray<Typ>.Pop: Typ;
  Var i: Integer;

  Begin
    i := High;
    Result := Getter(i);
    SetLength(i);
  End;}

hoika 8. Okt 2009 11:59

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Hallo,

was ist dass denn für eine Datei,
wo du alle 800 MB im Speicher haben musst ?


Heiko

greenmile 8. Okt 2009 12:12

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Ein RamDrive

himitsu 8. Okt 2009 12:21

Re: SetLength / Getmem / AllocMem out of memory Problem
 
na wenn das so ist ...

da dir windows dabei eh ständig den Speicher auslagert (ich gehe mal stark davon aus, daß du deinen Speicher nicht direkt im RAM reservierst und ist bei einem Array und ohne Änderung des delphieigenen Speichermanagers auch garnicht möglich)

nimm eine MMF, diese wird zwar auch ausgelagert, aber was soll's

greenmile 9. Okt 2009 11:54

Re: SetLength / Getmem / AllocMem out of memory Problem
 
Die Pipes scheinen irgendwie spez. Rechte zu benötigen, habe testhalber mal mit TMemoryStream rumgespielt und das klappt Sahne. Kann sogar mit SetSize mehr als 1 GByte erstellen. Scheint zu klappen ...


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:13 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