6

Disclaimer: Ich entschuldige mich für die Ausführlichkeit dieser Frage (ich denke, es ist ein interessantes Problem, obwohl!), Aber ich kann nicht herausfinden, wie um es prägnanter zu formulieren.Zugriff auf> 2,3,4GB Dateien in 32bit Prozess auf 64bit (oder 32bit) Windows

Ich habe Stunden der Forschung getan, wie auf den scheinbar von Möglichkeiten, unzählige, in denen das Problem des Zugriff auf Multi-GB-Dateien in einem 32-Bit-Prozess auf 64-Bit-Windows 7 zu lösen, von /LARGEADDRESSAWARE zu VirtualAllocEx AWE reicht. Ich bin ein wenig in der Lage, ein System mit mehreren Speicherabbildern in Windows zu schreiben (CreateFileMapping, MapViewOfFile usw.), kann jedoch dem Gefühl, dass es eine elegantere Lösung für dieses Problem gibt, nicht ganz entkommen. Außerdem bin ich mir der Boost-Interprozessor- und Iostream-Templates durchaus bewusst, obwohl sie ziemlich leichtgewichtig zu sein scheinen und einen ähnlichen Aufwand erfordern, um ein System zu schreiben, das nur Windows-API-Aufrufe verwendet (ganz zu schweigen von der Tatsache, dass ich bereits einen Speicher habe). gemappte Architektur, die unter Verwendung von Windows-API-Aufrufen teilweise implementiert wurde).

Ich versuche, große Datensätze zu verarbeiten. Das Programm ist auf vorkompilierte 32-Bit-Bibliotheken angewiesen, weshalb das Programm derzeit auch in einem 32-Bit-Prozess läuft, obwohl das System 64-Bit-fähig ist, mit einem 64-Bit-Betriebssystem. Ich weiß, dass es Wege gibt, auf denen ich Wrapper-Bibliotheken hinzufügen könnte, aber da es Teil einer größeren Codebasis ist, wäre es in der Tat ein bisschen ein Unternehmen. Ich setze die binären Header auf /LARGEADDRESSAWARE (auf Kosten der Verringerung meiner Kernel-Speicherplatz?), So dass ich bis zu etwa 2-3 GB adressierbaren Speicher pro Prozess, geben oder nehmen (abhängig von Heap-Fragmentierung, etc.) .

Hier ist das Problem: Die Datensätze sind 4 + GB, und DSP-Algorithmen laufen auf ihnen, die im Wesentlichen wahlfreien Zugriff über die Datei erfordern. Ein Zeiger auf das aus der Datei erzeugte Objekt wird in C# behandelt, die Datei selbst wird jedoch in C++ (mit P/Invoked) in den Speicher geladen (mit diesem partiellen Speicherabbildungssystem). Daher glaube ich, dass die Lösung leider nicht so einfach ist, einfach die Fensterung anzupassen, um auf den Teil der Datei zuzugreifen, auf den ich zugreifen muss, da ich im Wesentlichen die gesamte Datei in einen einzigen Zeiger abstrahieren möchte, von dem ich Methoden aufrufen kann Zugriff auf Daten fast überall in der Datei. Die Speicherarchitekturen basieren anscheinend auf der Aufteilung des singulären Prozesses in mehrere Prozesse. So würde ich zum Beispiel auf eine 6-GB-Datei mit 3x Prozessen zugreifen, von denen jeder ein 2-GB-Fenster für die Datei enthält. Ich müsste dann eine signifikante Menge an Logik hinzufügen, um Daten aus diesen verschiedenen Fenstern/Prozessen zu ziehen und neu zu kombinieren. VirtualAllocEx bietet anscheinend eine Methode, den virtuellen Adressraum zu vergrößern, aber ich bin immer noch nicht ganz sicher, ob dies der beste Weg ist, um darüber zu gehen.

Aber sagen wir, ich möchte, dass dieses Programm genauso "einfach" funktioniert wie ein singulärer 64bit Prozess auf einem 64bit System. Nehmen wir an, dass es mir egal ist, wenn ich mich prügele, ich möchte nur eine große Datei auf dem System manipulieren können, auch wenn nur 500 MB in den physischen Arbeitsspeicher geladen wurden. Gibt es eine Möglichkeit, diese Funktionalität zu erhalten, ohne ein etwas lächerliches, manuelles Speichersystem von Hand schreiben zu müssen? Oder gibt es einen besseren Weg als das, was ich durch SO und das Internet gefunden habe?

Dies ergibt sich für eine sekundäre Frage: Gibt es eine Möglichkeit zu begrenzen, wie viel physisches RAM von diesem Prozess verwendet werden würde? Was wäre zum Beispiel, wenn ich den Prozess auf nur 500 MB beschränken möchte, die gleichzeitig in physischen RAM geladen werden (während die Multi-GB-Datei auf der Festplatte gespeichert bleibt)?

Es tut mir leid für die lange Frage, aber ich habe das Gefühl, es ist eine anständige Zusammenfassung von dem, was viele Fragen (mit nur teilweise Antworten), die ich auf SO und das Netz insgesamt gefunden habe. Ich hoffe, dass dies ein Bereich sein kann, in dem eine definitive Antwort (oder zumindest einige Vor-/Nachteile) ausgearbeitet werden kann und wir alle etwas wertvolles lernen können!

+1

tl; dr, aber wenn Sie eine externe Bibliothek verwenden möchten: Qt kann "große Dateien" plattformübergreifend verarbeiten, jedoch nicht speicherabgebildet (auf 32-Bit-Plattformen). Aber es verwendet einen internen IO-Cache, der * eine vergleichbare Leistung * erreichen kann? – leemes

+0

Danke für den Kommentar, leemes (obwohl tl; dr ist etwas unhöflich zu sagen> _> ;;)! Ich habe mit einem internen IO-Cache nachgedacht, aber das scheint eine ziemlich große Menge an Komplexität einzuführen, was ich zu vermeiden versuche. Außerdem möchte ich vermeiden, zusätzliche Bibliotheken wie Qt zum Mix hinzuzufügen (Boost ist jedoch bereits integriert) –

+0

Begrenzung des Arbeitsspeichers, Sie könnten ein Windows-Job-Objekt verwenden und den Arbeitssatz begrenzen, der physischen RAM einschränkt. Leider denke ich, dass dies nur das Austauschen maximieren wird, also ist es nicht das, was Sie möglicherweise wollen. Ich nehme auch an, dass Sie über Memory-Mapped-Dateien Bescheid wissen und diese nicht Ihren Bedürfnissen entsprechen. –

Antwort

2

Sie könnten eine Accessor-Klasse schreiben, der Sie eine Basisadresse und eine Länge geben. Es gibt Daten zurück oder löst eine Exception aus (oder wie auch immer Sie über Fehlerbedingungen informieren wollen), wenn Fehlerbedingungen auftreten (außerhalb der Grenzen, usw.).

Dann, jedes Mal, wenn Sie aus der Datei lesen müssen, kann das Accessor-Objekt SetFilePointerEx() vor dem Aufruf ReadFile() verwenden. Sie können dann die Accessorklasse an den Konstruktor aller Objekte übergeben, die Sie beim Lesen der Datei erstellen. Die Objekte verwenden dann die Accessorklasse, um die Daten aus der Datei zu lesen. Dann gibt es die Daten an den Konstruktor des Objekts zurück, der es in Objektdaten parst.

Wenn Sie später in der Lage sind, auf 64-Bit zu kompilieren, können Sie die Accessorklasse nur ändern (oder erweitern), um stattdessen aus dem Speicher zu lesen.

Was die Menge an RAM von dem Verfahren verwendet Begrenzung .. das ist vor allem eine Frage der sicherstellen, dass A) Sie haben keine Speicherlecks (besonders obszön sind) und B) zu zerstören Objekte, die Sie nicht tun brauchen im Moment. Auch wenn Sie es später brauchen, aber die Daten werden sich nicht ändern ... einfach das Objekt zerstören. Erstellen Sie es später erneut, wenn Sie es benötigen, und lesen Sie die Daten aus der Datei erneut.

+1

Hmm ... das hört sich nach einer interessanten Idee an, inetknght! Danke für die Eingabe! Obwohl dies klingt wie eine gute Möglichkeit, um über die Datei zu lesen, erfordert es immer noch die Zugabe von einer gewissen Menge an Logik beim Verschieben von Ansichten manuell über die Datei, obwohl ich zustimmen, dass die Verwendung eines erweiterbaren Accessor wäre groß, in dass nur die Accessor-Klasse geändert werden müsste, wenn diese jemals in Richtung 64-Bit verschoben wird. Dies kann die endgültige Implementierung sein, wenn es keine anderen Möglichkeiten gibt, die Datei leicht von einem anderen Konstrukt verwalten zu lassen. –

Verwandte Themen