Delphi-PRAXiS
Seite 4 von 5   « Erste     234 5      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Speicherlast des Programms mittels GetMemoryManagerState - komischer Wert (https://www.delphipraxis.net/154621-speicherlast-des-programms-mittels-getmemorymanagerstate-komischer-wert.html)

Bambini 9. Nov 2016 09:15

AW: Speicherlast des Programms mittels GetMemoryManagerState - komischer Wert
 
Zitat:

Zitat von Jim Carrey (Beitrag 1353053)
Das mit den Forms mache ich teilweise auch so. Ich erstelle komplexe Formulare erst wenn sie wirklich benötigt werden.
Das verschnellert den Programmstart und hält den Speicherverbrauch ein wenig niedriger.
Hat einzig den Nachteil der Usability im Sinne von "Wenn ich da drauf klicke, soll sofort was passieren" - ist dann eben nicht der Fall.

... das wäre doch eine schöne Aufgabe für einen Hintergrund-Thread.

Benmik 9. Nov 2016 14:32

AW: Speicherlast des Programms mittels GetMemoryManagerState - komischer Wert
 
Jetzt habe ich Zacherls Vorschlag implementiert. Funktioniert auch. Aufgrund der Streams kann die Größe der Bitmaps jetzt genau angegeben werden. Der Taskmanager - der ja augenscheinlich erschütternd unzuverlässig ist - zeigt nun statt 500 MB nur noch 180 MB an.
Die ganze Geschichte läuft aber merklich langsamer ab als mit den direkt gespeicherten Bitmaps. Die Erstellung der Bitmaps/Streams ist in asychrone Threads ausgelagert, auch damit scheint es Probleme zu geben, das Programm hängt sich bei forcierter Belastung auf ("forcierte Belastung" heißt, ich halte die Weiter-Taste gedrückt und nudle 100 Bilder durch, dadurch müssen pausenlos Bilder geladen, gelesen und verworfen werden). Hab's jetzt aber noch nicht richtig handoptimiert, mal sehen.

Bambini 9. Nov 2016 15:13

AW: Speicherlast des Programms mittels GetMemoryManagerState - komischer Wert
 
Zitat:

Zitat von Benmik (Beitrag 1353138)
Jetzt habe ich Zacherls Vorschlag implementiert. Funktioniert auch. Aufgrund der Streams kann die Größe der Bitmaps jetzt genau angegeben werden. Der Taskmanager - der ja augenscheinlich erschütternd unzuverlässig ist - zeigt nun statt 500 MB nur noch 180 MB an.
Die ganze Geschichte läuft aber merklich langsamer ab als mit den direkt gespeicherten Bitmaps.

Nun ja, der Stream liegt damit jetzt nicht mehr im RAM sondern alle auf der Platte. Auch wenn Windows hierbei einiges puffert. So schnell wie RAM ist eine Platte nie ;-)

Benmik 9. Nov 2016 16:00

AW: Speicherlast des Programms mittels GetMemoryManagerState - komischer Wert
 
Laut Zacherl müsste das alles im RAM liegen.

Bambini 9. Nov 2016 16:43

AW: Speicherlast des Programms mittels GetMemoryManagerState - komischer Wert
 
Zitat:

Zitat von Benmik (Beitrag 1353160)
Laut Zacherl müsste das alles im RAM liegen.

wenn du diesen Code verwendest:
Delphi-Quellcode:
 inherited Create(CreateFile(PChar(TPath.GetTempFileName), GENERIC_READ or GENERIC_WRITE,
    0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY or
    FILE_ATTRIBUTE_NOT_CONTENT_INDEXED or FILE_ATTRIBUTE_HIDDEN or FILE_FLAG_DELETE_ON_CLOSE, 0));
dann nicht.

Zacherl 9. Nov 2016 17:13

AW: Speicherlast des Programms mittels GetMemoryManagerState - komischer Wert
 
Zitat:

Zitat von Benmik (Beitrag 1353160)
Laut Zacherl müsste das alles im RAM liegen.

Zitat:

Zitat von Bambini (Beitrag 1353165)
Zitat:

Zitat von Benmik (Beitrag 1353160)
Laut Zacherl müsste das alles im RAM liegen.

wenn du diesen Code verwendest:
Delphi-Quellcode:
 inherited Create(CreateFile(PChar(TPath.GetTempFileName), GENERIC_READ or GENERIC_WRITE,
    0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY or
    FILE_ATTRIBUTE_NOT_CONTENT_INDEXED or FILE_ATTRIBUTE_HIDDEN or FILE_FLAG_DELETE_ON_CLOSE, 0));
dann nicht.

Beachte das
Delphi-Quellcode:
FILE_ATTRIBUTE_TEMPORARY
Flag. Solange dem System genug freier physikalischer zur Verfügung steht und nichts ausgelagert werden muss, befindet sich die Datei tatsächlich komplett im RAM.

Zitat:

Zitat von Benmik (Beitrag 1353138)
Der Taskmanager - der ja augenscheinlich erschütternd unzuverlässig ist - zeigt nun statt 500 MB nur noch 180 MB an.

Wie gesagt, der Taskmanager zeigt mit dem WorkingSet nur den momentan tatsächlich physikalisch verwendeten Speicher des Prozesses an. Also exklusive ausgelagerter Pages. Daten, die du in den FileCache lädst sind darin auch nicht enthalten.

Zitat:

Zitat von Benmik (Beitrag 1353138)
Die ganze Geschichte läuft aber merklich langsamer ab als mit den direkt gespeicherten Bitmaps. Die Erstellung der Bitmaps/Streams ist in asychrone Threads ausgelagert, auch damit scheint es Probleme zu geben, das Programm hängt sich bei forcierter Belastung auf ("forcierte Belastung" heißt, ich halte die Weiter-Taste gedrückt und nudle 100 Bilder durch, dadurch müssen pausenlos Bilder geladen, gelesen und verworfen werden). Hab's jetzt aber noch nicht richtig handoptimiert, mal sehen.

Tatsächlich haben auch diese speziellen Streams einen Performance Nachteil gegenüber der direkten Speicherung im RAM. Das liegt mitunter daran, dass Windows die Dateien im Filesystem "simuliert" und auch Eigenschaften wie die letzte Zugriffszeit etc. jeweils aktualisiert. Normalen FileStreams sind sie aber trotzdem noch weit überlegen.

Optimieren könntest du noch, indem du nach dem Laden des ersten Bildes im Hintergrund schon anfängst Nummer zwei (und evtl. danach noch Nummer 3) zu laden, etc. Sind sicher noch einige Verbesserungen drinnen.

t.roller 9. Nov 2016 19:00

AW: Speicherlast des Programms mittels GetMemoryManagerState - komischer Wert
 
Liste der Anhänge anzeigen (Anzahl: 1)
Schon mal an RAMDisk gedacht?

Benmik 9. Nov 2016 19:07

AW: Speicherlast des Programms mittels GetMemoryManagerState - komischer Wert
 
Zitat:

Zitat von Zacherl (Beitrag 1353166)
Optimieren könntest du noch, indem du nach dem Laden des ersten Bildes im Hintergrund schon anfängst Nummer zwei (und evtl. danach noch Nummer 3) zu laden...

Das geschieht ja mit den asynchronen Threads, und da ich einen Threadpool mit
Delphi-Quellcode:
MaxThreads := 2 * System.CPUCount;
verwende, werden sogar alle BMP gleichzeitig geladen (und geht bei einer SSD richtig schnell, bei einer normalen Festplatte ist das eher kontraproduktiv). Dieses Laden geht bei Bitmaps viel schneller. Aber daran könnte ich wohl noch schrauben.

RAMDisk sieht sehr interessant aus, ist für meine Anwendung aber eher nichts (müsste erst eingerichtet werden, der Platzbedarf ändert sich dauernd mit den Einstellungen und der Größe der Bitmaps usw.). Aber für andere Sachen wäre das vielleicht wirklich interessant!

PS:
Ich habe jetzt in einer Schleife 100 Bilder einzeln geladen, dekomprimiert, in den Stream geladen und wieder freigegeben. Das dauerte etwa 37 Sekunden, also eine drittel Sekunde pro Bild. Das Wiederauslesen des Streams und Laden in ein Bitmap verlängerte die Prozedur um 5 Sekunden, also eine Zwanzigstelsekunde je Bitmap. Da scheint mir kaum Potenzial für Verbesserungen zu sein. Ich gucke mir nochmal das Management der Threads an.

PPS:
Das RAM-Disk-Tool ImDisk findet man jetzt hier, oder besser noch bei Sourceforge mit Konfigurator.

PPPS:
Von der RAM-Disk aus läuft der Prozess mit den 100 Bildern in 35 (!) Sekunden. Das scheint mir kein echtes Optimierungspotenzial.

Benmik 12. Nov 2016 20:01

AW: Speicherlast des Programms mittels GetMemoryManagerState - komischer Wert
 
Ich habe jetzt eine Reihe von Versuchen durchgeführt, die die alte (Speichern von TBitmap) mit der neuen (TMemoryFileStream) Methode vergleicht, mit einem etwas zwiespältigen Ergebnis.
  • Mit TMemoryFileStream kann ich abenteuerliche Werte für die Anzahl der vorzuladenden Bilder eingeben, zum Beispiel 30 vor und 30 zurück, ohne das es knallt. Gut!!
  • Als Extremwert habe ich 99 vorzuladende Bilder eingestellt (Maximalwert). Hierbei belegt der Filecache (ich habe 8 GB RAM) laut Ressourcenmonitor etwa 6 GB, uneingeschränkt frei noch 80 MB. Das ist eindrucksvoll.
  • Das Laden und Anzeigen der Bilder dauert ziemlich zuverlässig doppelt so lange wie mit TBitmaps.
  • Dies liegt am Speichern im TMemoryFileStream. Das Laden der JPG von der SSD ist vernachlässigbar, 15 ms. Das Dekodieren der Bitmaps aus den JPG dauert sehr einheitlich etwa 170 ms.
  • Bei Methode 2 kommt nun noch das Speichern im Stream dazu. Das dauert 140 bis 170 ms, dazwischen aber immer wieder über 500 ms.
  • Das Laden mit den Bitmaps wirkt schneller und spritziger, reagibler. Das "Durchnudeln" mit gedrückter Vorwärtstaste geht richtig zügig.
Jetzt kann ich mich entscheiden, was ich will, Leistung oder Robustheit. Vermutlich ist Letzteres wichtiger.

Zacherl 13. Nov 2016 19:38

AW: Speicherlast des Programms mittels GetMemoryManagerState - komischer Wert
 
Mir kommt da grade noch eine Idee:

Dein größtes Problem ist ja erstmal die 2GiB Grenze des virtuellen Adressraums. Du könntest dir eine weitere (Stream-)Klasse basteln, in der du die Daten als Memory Mapped File (MSDN-Library durchsuchenCreateFileMapping, MSDN-Library durchsuchenMapViewOfFile) speicherst. Solange mindestens ein Handle auf das MMF offen ist, wird es vom System nicht gelöscht, selbst dann, wenn du den Dateiinhalt mit MSDN-Library durchsuchenUnmapViewOfFile wieder aus deinem Prozessspeicher entfernst.
Wenn du jetzt jeweils nur das aktuell geöffnete Bild mappst, hast du auch immer nur einen großen zusammenhängenden Speicherblock in deinem virtuellen Adressraum liegen und würdest zumindest diese Ursache für eine
Delphi-Quellcode:
EOutOfMemory
Exception eliminieren. Sollte dein physikalischer RAM irgendwann nicht mehr ausreichen, fängt Windows halt an RAM in die Auslagerungsdatei auszulagern.

Zu bedenken ist hierbei allerdings, dass du mit dieser Methode natürlich die Leistung des ganzen System beeinträchtigen kannst, wenn du den kompletten RAM mit deinen MMFs füllst. Wobei selbst hier der Overhead nicht allzu fatal sein sollte.


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:49 Uhr.
Seite 4 von 5   « Erste     234 5      

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