(gelöst) [WinAPI] Lebensdauer Datei-HANDLE bei Mapping

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
Krishty
Establishment
Beiträge: 8350
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

(gelöst) [WinAPI] Lebensdauer Datei-HANDLE bei Mapping

Beitrag von Krishty »

Hi,

der übliche Weg, um via WinAPI eine Datei im Speicher abzubilden ist:

HANDLE file = CreateFile()
HANDLE map = CreateFileMapping(file)
void * pointer = MapViewOfFile(map)

und bei der Freigabe umgekehrt:

UnmapViewOfFile(pointer)
CloseHandle(map)
CloseHandle(file)

Meine Frage ist nun: Darf ich file auch sofort wieder schließen, nachdem CreateFileMapping() damit aufgerufen wurde?

Die MSDN scheint sich dazu nicht zu äußern; sie sagt nur, dass sowohl map als auch file wieder freigegeben werden sollten (und zwar möglichst nach pointer, um Speicherlecks zu vermeiden). Bei einem schnellen Test meinerseits schien es keinerlei Probleme zu verursachen.

Falls also jemand Informationen dazu findet, ob der Kernel Reference Count des Datei-HANDLEs durch CreateFileMapping() inkrementiert wird: bitte immer her damit.

Gruß, Ky
Zuletzt geändert von Krishty am 28.01.2012, 08:43, insgesamt 1-mal geändert.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1746
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [WinAPI] Lebensdauer Datei-HANDLE bei Mapping

Beitrag von dot »

http://msdn.microsoft.com/en-us/library ... 66882.aspx
Although an application may close the file handle used to create a file mapping object, the system holds the corresponding file open until the last view of the file is unmapped.
;)
Benutzeravatar
Krishty
Establishment
Beiträge: 8350
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [WinAPI] Lebensdauer Datei-HANDLE bei Mapping

Beitrag von Krishty »

Danke; das hatte ich übersehen.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa366532 hat geschrieben:When each process finishes using the file mapping object and has unmapped all views, it must close the file mapping object's handle and the file on disk by calling CloseHandle. These calls to CloseHandle succeed even when there are file views that are still open. However, leaving file views mapped causes memory leaks.
Also: Die Datei bleibt offen, bis auch die letzte Adresse durch UnmapViewOfFile() freigegeben wurde – das ist an sich erstmal fantastisch.

Allerdings bleibt der Speicher, den man von MapViewOfFile() erhalten hat, nur bis zum Schließen des letzten der beiden HANDLEs freigebbar, und danach hat man zwangsläufig ein Speicherleck.

Sehe ich das soweit richtig?
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1746
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [WinAPI] Lebensdauer Datei-HANDLE bei Mapping

Beitrag von dot »

Es ist auch nicht ganz klar ob du die Datei gleich nach CreateFileMapping() schließen kannst oder erst wenn das Mapping gemapped wurde. Ich würde mal vermuten dass du sie theoretisch gleich schließen kannst.
Was das Memory Leak angeht bin ich mir nicht ganz sicher was du meinst. So wie ich das verstehe geht's darum, dass du eben UnmapViewOfFile() aufrufen musst bevor du das FileMapping freigibst.
Benutzeravatar
Krishty
Establishment
Beiträge: 8350
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [WinAPI] Lebensdauer Datei-HANDLE bei Mapping

Beitrag von Krishty »

dot hat geschrieben:So wie ich das verstehe geht's darum, dass du eben UnmapViewOfFile() aufrufen musst bevor du das FileMapping freigibst.
Ja; so habe ich das auch verstanden.

Ein schneller Test hat übrigens ergeben, dass der Speicher trotzdem freigegeben wird: Im Fall von

HANDLE file = CreateFile()
HANDLE map = CreateFileMapping(file)
void * pointer = MapViewOfFile(map)
CloseHandle(map)
CloseHandle(file)

// Hier lesbare Daten

before = GlobalMemoryStatusEx().ullAvailVirtual
UnmapViewOfFile(pointer)
delta = GlobalMemoryStatusEx().ullAvailVirtual - before


ist delta exakt so groß wie die Datei, deren Ansicht unmapped wurde.

Das wäre für mich enorm angenehm, weil ich Memory-mapped Files nach ihrer Erzeugung schlicht als Standard-Blobs durch Zeiger und Größe implementieren könnte, ohne mich um Handles kümmern zu müssen. Der Hinweis der MSDN mit dem Speicherleck hinterlässt bei diesem Gedanken aber ein sehr mulmiges Gefühl …
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1746
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: [WinAPI] Lebensdauer Datei-HANDLE bei Mapping

Beitrag von dot »

Ok, man kann den Satz imo auch so interpretieren, dass man einfach nur Unmappen muss, egal wann...
Benutzeravatar
Krishty
Establishment
Beiträge: 8350
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: [WinAPI] Lebensdauer Datei-HANDLE bei Mapping

Beitrag von Krishty »

dot hat geschrieben:Ok, man kann den Satz imo auch so interpretieren, dass man einfach nur Unmappen muss, egal wann...
Dann interpretiere ich ihn sehr gern so :) Danke schonmal; ich brauche ab und an noch Hilfe beim Lesen der MSDN.

Anstellen will ich damit das Übliche – man kriegt irgendwo Speicher; arbeitet damit; und gibt ihn wieder frei – egal, ob der Inhalt aus der Exe, von Stapel- oder Freispeicher, oder aus einer Datei kommt.

Dafür muss ich allerdings von einer Basisklasse ableiten, die in bester RAII-Manier sofort mit der fertigen Adresse initialisiert werden will. Da Visual C++ noch keine Delegating Constructors unterstützt und das Initialisieren durch eine freie Funktion eklige Kopier- und Schiebesemantik sowie eine öffentliche struct und einen friend erfordert, habe ich mir bisher durch eine verschachtelte Hierarchie beholfen, bei der die Aufrufreihenfolge Datei öffnen; Ansicht erzeugen; mappen (und das umgekehrte Aufräumen) garantiert ist.

Da ich nun aber nichts mehr außer Adresse und Größe brauche und trotzdem sauber freigeben kann, komme ich mit einer einzelnen direkt abgeleiteten Klasse und einer privaten statischen Funktion aus. Das spart auf einen Schlag fast 3 KiB Maschinentext, die vorher immer durchgelaufen sind. Sehr sehr angenehm.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Krishty
Establishment
Beiträge: 8350
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (gelöst) [WinAPI] Lebensdauer Datei-HANDLE bei Mapping

Beitrag von Krishty »

Noch ein wenig Gequatsche hinterher:

Mir ist ein Unterschied zwischen CreateFileMappingA() und CreateFileMappingW() aufgefallen:
  • Die ANSI-Version führt 20, 30 Befehle auf den Parametern durch und ruft dann das importierte CreateFileMappingNumaW() in KernelBase.dll auf. Dort beginnt das eigentliche Mapping.
     
  • Die UTF-16-Version ist nur ein Platzhalter, der zum aus KernelBase.dll importierten CreateFileMappingW() weiterleitet. Dort wird dann mit dem Mapping begonnen.
Beide Versionen leiten also zur UTF-16-Implementierung weiter (was auch nicht verwundert); die ANSI-Version aber zu einer NUMA-Implementierung; die UTF-16-Version dagegen zu einer nicht-NUMA-Implementierung.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
dot
Establishment
Beiträge: 1746
Registriert: 06.03.2004, 18:10
Echter Name: Michael Kenzel
Kontaktdaten:

Re: (gelöst) [WinAPI] Lebensdauer Datei-HANDLE bei Mapping

Beitrag von dot »

Das ist nicht verwunderlich, da der Windows Kernel intern UTF-16 basiert ist. Sämtliche ANSI Varianten werden also normalerweise nichts anderes tun als nach UTF-16 konvertieren und dann die Unicode Funktion aufzurufen.
Kanns sein dass CreateFileMappingW() aus der KernelBase.dll selbst auch nur die Numa Funktion aufruft? Denn ansonsten ist das schon etwas merkwürdig.

Achja, bei CreateFileMappingNuma() sagt die MSDN übrigens:
To fully close a file mapping object, an application must unmap all mapped views of the file mapping object by calling the UnmapViewOfFile function and then close the file mapping object handle by calling the CloseHandle function.

These functions can be called in any order. The call to the UnmapViewOfFile function is necessary, because mapped views of a file mapping object maintain internal open handles to the object, and a file mapping object does not close until all open handles to it are closed.
Das dürfte dich etwas ruhiger schlafen lassen ;)
Benutzeravatar
Krishty
Establishment
Beiträge: 8350
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: (gelöst) [WinAPI] Lebensdauer Datei-HANDLE bei Mapping

Beitrag von Krishty »

dot hat geschrieben:Das ist nicht verwunderlich, da der Windows Kernel intern UTF-16 basiert ist. […]
Darum schreibe ich ja; es verwundert auch nicht ;)
dot hat geschrieben:Kanns sein dass CreateFileMappingW() aus der KernelBase.dll selbst auch nur die Numa Funktion aufruft? Denn ansonsten ist das schon etwas merkwürdig.
Ich kann nichts derartiges erkennen; der einzige Aufruf geht direkt an __imp_NtCreateSection() (wie auch in CreateFileMappingNumaW()). Es ist möglich, dass das Einrichten der NUMA-Parameter irgendwo im umliegenden Maschinentext geschieht; oder dass der CreateFileMappingNumaW()-Aufruf der ANSI-Version mit Standardparametern geschieht, so dass bei __imp_NtCreateSection() am Ende das selbe ankommt. In diesem Fall würde mich aber wundern, warum es zwei Funktionen unterschiedlichen Namens aber gleichen Zwecks in KernelBase.dll gibt.
dot hat geschrieben:Achja, bei CreateFileMappingNuma() sagt die MSDN übrigens:
To fully close a file mapping object, an application must unmap all mapped views of the file mapping object by calling the UnmapViewOfFile function and then close the file mapping object handle by calling the CloseHandle function.

These functions can be called in any order. The call to the UnmapViewOfFile function is necessary, because mapped views of a file mapping object maintain internal open handles to the object, and a file mapping object does not close until all open handles to it are closed.
Das dürfte dich etwas ruhiger schlafen lassen ;)
Ohja; perfekt! Verdammt, warum ist diese Information ausgerechnet dort versteckt …
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Antworten