Entwickler-Ecke

Dateizugriff - DLL-Laden unter Windows


Mathematiker - Sa 24.12.11 11:45
Titel: DLL-Laden unter Windows
Für ein etwas größeres Projekt muss ich rund 5000, meist kleinere, GIF- und JPG-Bilder verwalten und gegebenenfalls laden und anzeigen.
Bisher liegen die Dateien einzeln in mehreren Ordnern, sind im Moment in der Summe 80 MByte groß, belegen aber gute 95 MByte. Außerdem ist das Kopieren auf verschiedene Datenträger langwierig.
Aus diesem Grund möchte ich die Dateien in eine einzige Resourcen-DLL (wahrscheinlich um 80 MByte) packen.
Erste Versuche mit gerade mal 200 Bildern sind ganz erfolgreich. Für das Laden eines Bildes rufe ich loadlibrary, danach den Stream und gebe mit freelibrary alles wieder frei.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
procedure gif_dll_laden(const kk:string;image:timage);
var hl :HINST; Stream: TStream; GIF: TGIFImage; Bitmap: TBitmap;
begin
  hl := LoadLibrary('bgif.dll');
  try  Stream := TResourceStream.Create(hl,kk,'GIF');
  try  GIF := TGIFImage.Create;
  try  GIF.LoadFromStream(Stream);
      Image.Picture.Assign(nil);
      Bitmap := TBitmap.Create;
      try
        Bitmap.Assign(GIF);
        Image.Picture.Assign(Bitmap);
      finally Bitmap.Free; end;
    finally GIF.Free; end;
  finally Stream.Free; end;
  finally FreeLibrary(hl); end;
end;

Allerdings habe ich ein Problem, da mir nicht klar ist, wie Windows derartige Resourcen-DLLs verwaltet.
Angenommen ich möchte nur ein kleines GIF-Bild von etwa 2 kbyte aus der DLL laden, frage ich mich, wie Windows vorgeht.
Wird die ganze(!) DLL in den Speicher geladen (das wäre extrem langsam und damit untauglich) oder wird nur die Liste der Resourcen und die Adresse des Bildes geladen und danach gezielt der Speicherbereich, welcher das gewünschte Bild enthält.
Da es zukünftig wahrscheinlich noch mehr Bilder werden, wird eine solche DLL auch immer größer.
Vielleicht kann mir jemand helfen.

Moderiert von user profile iconGausi: Delphi-Tags hinzugefügt


Martok - Sa 24.12.11 15:08

Hallo und :welcome: in der Entwickler-Ecke!

Soweit ich weiß, mappt LoadLibrary alle Segmente in den Speicher. Dürfte aber bedeuten, dass die nicht von der Platte gelesen werden, bis wirklich was passiert - also sofort ;) Ich denke, das Resourcensegment wird dann komplett gelesen... aber wirklich weiß ich das nicht.


Spricht etwas gegen ein einfaches Zip-Archiv?


Mathematiker - Sa 24.12.11 20:02

Vielen Dank für die schnelle Antwort.
Zip-Archiv klingt gut. Ich müsste aber aus diesem Archiv mit dem Delphi-Programm das gewünschte Bild lesen. Geht das überhaupt ohne Zusatzkomponenten?


jaenicke - Sa 24.12.11 21:00

Da du in deinem Profil deine Delphiversion nicht angegeben hast, kann dir diese Frage niemand direkt beantworten. Falls du XE2 hast, lautet die Antwort ja, bei älteren Versionen nein.

Bei Delphi XE2 kannst du die Unit System.Zip in die uses schreiben und hast dann direkt mit TZipFile eine native Kapselung des ZIP Formats zur Verfügung.

Für Delphi XE und früher kann ich dir Abbrevia empfehlen. Das kannst du unter der MPL nutzen und ist sehr einfach.


Mathematiker - Sa 24.12.11 22:24

Ich arbeite noch mit der "Steinzeit"-Version Delphi 5, die mir aber bisher alles geliefert hat, was ich brauchte.
Außerdem gehöre ich noch zu denen, die gern alles selbst erstellen.
Ich habe erst einmal Abbrevia geladen und werde sehen, ob es unter Delphi 5 funktioniert.
Dank für den Hinweis.

Nachtrag:
Wie zu erwarten, weigert sich mein Delphi 5 Abbrevia zu nutzen.
Ich werde etwas suchen, vieleicht find ich eine Alternative. Wenn nicht, erstelle ich meine große Resourcen-DLL (wird einiges an Arbeit) und dann sehe ich ja, ob es noch vernünftige Ladezeiten gibt.


Martok - Sa 24.12.11 22:42

Abbrevia fand ich immer sinnlos groß und kompliziert. Ich kann KAZip empfehlen, da war allerdings irgendwann mal ein Bug beim extrahieren in einen MemoryStream. Der äußert sich allerdings in einer Exception, ist also sehr offensichtlich ;)

Steht zwar D6/7 dran, aber soweit ich mich erinnern kann hatte ich das auch mal mit D4 zum laufen bekommen.


BenBE - So 25.12.11 00:15

Es gibt mit LoadLibraryEx die Möglichkeit Windows die Verwendung der DLL mitzuteilen. Damit ist es möglich, dass man Windows den teilweise recht aufwändigen Schritt der Relocation von Code-Segmenten erspart und stattdessen wirklich nur die Datensegmente in den Speicher läd. Im Zweifelsfalle möchtest Du deine Resourcen-DLL aber auch nicht für jedes Bild neu laden, sondern einmal beim Programmstart holen und dann basierend auf dieser einmalig geladenen Kopie alle Resourcen lesen. Damit ersparst Du dir das ständige Lesen von der Platte.


Delete - Mo 26.12.11 11:40

JPG-Files in ein ZIP-File zu packen macht keinen Sinn.


Boldar - Mo 26.12.11 11:57

Doch, wenn es so viele sind. Das verringert enorm die fragmentierung und erhöht die Kopiergeschwindigkeit.


Delete - Mo 26.12.11 14:09

Die Komponente TPictureContainer ist vermutlich besser geeignet:
Hier enthalten:
http://www.delphipages.com/download.php?id=2188


jaenicke - Mo 26.12.11 15:08

Die Komponente hat den gravierenden Nachteil, dass die Dateien direkt in der .exe landen. Für Anfänger mag das erst einmal interessant klingen, weil es "cool" ist, wenn es nur eine Datei ist, aber für 90% der normalen Anwendungsfälle taugt das weniger.

Das hat mehrere Gründe:


Martok - Mo 26.12.11 16:14

user profile iconhathor hat folgendes geschrieben Zum zitierten Posting springen:
JPG-Files in ein ZIP-File zu packen macht keinen Sinn.
Ich hab nie was von komprimieren gesagt. ZIP kann auch "store" statt "deflate".

user profile iconBoldar hat folgendes geschrieben Zum zitierten Posting springen:
Doch, wenn es so viele sind. Das verringert enorm die fragmentierung und erhöht die Kopiergeschwindigkeit.
Sagen wir "wenn es viele kleine sind". Viele Dateien die einzeln nicht mal ein Cluster füllen würden verschwenden extrem Performance.


Delete - Mo 26.12.11 17:46

Anregung:
Pictures inside a database
http://delphi.about.com/od/database/l/aa030601a.htm


jaenicke - Mo 26.12.11 17:50

Dass das geht, ist klar, aber ich sehe da eigentlich nur Nachteile gegenüber z.B. einem Zip-Archiv. :gruebel: (Langsamer, keine Baumstruktur, Dateiformat muss zusätzlich verwaltet werden, schlecht durch den Anwender änderbar, ...)

Worin siehst du denn da einen Vorteil?


Delete - Di 27.12.11 01:54

Ich finde eine Bilder-Datenbank sehr reizvoll, weil sie beliebig erweiterbar ist, z.B. mit Bild-Beschreibungen (Autor, Datum, Kamera, Ort, MP3-Files mit Soundausgabe oder AVI-Filmchen, individuelle Einstellung der Dia-Wechsel, etc.)

3 Anhänge: Bitte die Inline-Anhänge einblenden


baka0815 - Di 27.12.11 10:50

Dann aber doch eher SQLite als Access...


Mathematiker - Mi 08.02.12 00:22

Mittlerweile habe ich über 2500 GIFs, 600 animierte GIFs und 1200 JPG-Dateien in jeweils eine DLL gepackt. Diese haben 22 MByte, 15 MByte und 28 MByte Umfang, sind also noch nicht sehr groß.
Dennoch kann ich jetzt schon feststellen, dass mit dem Tipp
user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:
Es gibt mit LoadLibraryEx die Möglichkeit Windows die Verwendung der DLL mitzuteilen.

Windows (Vista und 7) bei einem Aufruf eines Bildes in den DLLs nur die jeweils benötigten Daten ruft.
Fazit: Durch das Packen in die DLLs wurde die Ladezeit für mehrere Bildaufrufe sogar noch gesenkt! Ein Test, bei dem einmal die einzelnen Dateien von der Festplatte geladen wurden, zum anderen aus einer DLL heraus, ergab einen klaren Geschwindigkeitsgewinn für die DLL.
Damit ist mein Problem gelöst.
Vielen Dank für die Hinweise. :lol:

Mathematiker


Mathematiker - Mo 05.03.12 22:18

Hallo,
ich muss das Thema noch einmal aufgreifen, da ich mittlerweile bei einem Gesamtumfang von 100 MByte DLL bin und es noch mehr wird.
Da ich mich schon mit Computern herumgeärgert habe, als die meisten im Forum noch nicht geboren waren, bekomme ich ein Problem nicht aus dem Kopf: Eines der Hauptkriterien für ein gutes Programm war stets die minimale(!) Nutzung des Hauptspeichers. Mein erster PC hatte gerade mal 64 kbyte Hauptspeicher, wirklich!

Nun frage ich mich, wie weit man heute einen Rechnerspeichner belasten darf. Lese ich die DLL zu Programmbeginn ein, bekomme ich zwar einen Geschwindigkeitsgewinn während des Programmlaufs, der vom Programm genutzte Speicher erreicht aber schnell die 100 MByte.
Hat jemand eine Empfehlung, wieviel man noch vertretbar als Arbeitsspeicher "okkupieren" darf oder ist eine solche Frage in Zeiten von Gigabyte-Speichern sinnlos? :?!?:

Grüße
Mathematiker


jaenicke - Mo 05.03.12 22:47

Das kommt auf das Programm und dessen Zielgruppe an. Wenn die Nutzer größtenteils einen starken PC haben, kannst du das auch nutzen. Ich kenne aber auch viele, die nicht so viel RAM haben. Da wäre das eher ungünstig.

Wenn jemand nicht so viel RAM hat, wird der Speicher auf die Festplatte ausgelagert. Dann kann es sein, dass du eine deutlich geringere Geschwindigkeit hast als z.B. mit MMFs. Solange genug Speicher da ist, sollte deine jetzige Lösung aber nicht viel langsamer sein als MMFs.


Delete - Di 06.03.12 11:03

GetMaxAppAddress : 1,99 GB (2147418111)
GetMinAppAddress : 64 KB (65536)

Maximaler Speicher, der einer EXE zugeteilt wird: GetMaxAppAddress - GetMinAppAddress


t.roller - So 05.06.16 14:25

Bei einer 64Bit-EXE sieht das ganz anders aus:

EXE 64Bit:
GetMaxAppAddress: 140.737.488.289.791 = 7FFFFFFEFFFF Hex
GetMinAppAddress: 65536 = 10000 Hex
Maximaler Speicher, der einer EXE zugeteilt wird:
GetMaxAppAddress - GetMinAppAddress: 140.737.488.224.255 = 7FFFFFFDFFFF Hex