Im Speicher abgebildete Dateien

Eine Speicherabbilddatei enthält den Inhalt einer Datei im virtuellen Speicher. Diese Zuordnung zwischen einer Datei und Speicherplatz ermöglicht es einer Anwendung mit mehreren Prozessen, die Datei durch direktes Lesen und Schreiben im Arbeitsspeicher zu ändern. Sie können verwalteten Code verwenden, um auf die gleiche Weise auf im Speicher abgebildete Dateien zuzugreifen wie native Windows-Funktionen. Dies wird unter Verwalten von im Speicher abgebildeten Dateien beschrieben.

Es gibt zwei Arten von Speicherabbilddateien:

  • Beibehaltene Speicherabbilddateien

    Persistent gespeicherte Dateien sind Speicherabbilddateien, die einer Quelldatei auf einem Datenträger zugeordnet sind. Wenn der letzte Prozess die Verwendung der Datei beendet, werden die Daten in der Quelldatei auf dem Datenträger gespeichert. Diese Speicherabbilddateien eignen sich für extrem große Quelldateien.

  • Nicht beibehaltene Speicherabbilddateien

    Nicht persistent gespeicherte Dateien sind Speicherabbilddateien, die keiner Datei auf einem Datenträger zugeordnet sind. Wenn der letzte Prozess die Verwendung der Datei beendet, gehen die Daten verloren, und die Datei wird von der Garbage Collection freigegeben. Diese Dateien eignen sich zum Erstellen von freigegebenen Speicherbereichen für die prozessübergreifende Kommunikation (IPC).

Prozesse, Ansichten und Verwalten des Arbeitsspeichers

Speicherabbilddateien können für mehrere Prozesse verwendet werden. Prozesse können mithilfe eines allgemeinen Namens der gleichen Speicherabbilddatei zugeordnet werden. Dieser allgemeine Name wird von dem Prozess zugewiesen, durch den die Datei erstellt wird.

Zur Verwendung einer Speicherabbilddatei müssen Sie eine Ansicht der gesamten Speicherabbilddatei oder eines Teils davon erstellen. Sie können auch mehrere Ansichten für identische Teile der Speicherabbilddatei und dadurch parallelen Arbeitsspeicher erstellen. Parallele Ansichten müssen aus der gleichen Speicherabbilddatei erstellt werden.

Mehrere Ansichten können auch erforderlich sein, wenn die Datei größer als der für die Speicherzuordnung verfügbare logische Speicher der Anwendung ist (2 GB auf einem 32-Bit-Computer).

Zwei Arten von Ansichten werden verwendet: die Streamzugriffsansicht und die Ansicht für direkten Zugriff. Verwenden Sie für den sequenziellen Zugriff auf eine Datei Streamzugriffsansichten. Dies wird für nicht dauerhaft gespeicherte Dateien und IPC empfohlen. Die Ansichten für direkten Zugriff werden beim Arbeiten mit persistent gespeicherten Dateien vorgezogen.

Der Zugriff auf im Speicher abgebildete Dateien erfolgt über den Speicher-Manager des Betriebssystems. Die Datei wird daher automatisch in eine Reihe von Seiten partitioniert und nach Bedarf verwendet. Die Speicherverwaltung wird automatisch ausgeführt.

Die folgende Abbildung zeigt, wie für mehrere Prozesse gleichzeitig mehrere überlappende Ansichten derselben Speicherabbilddatei vorhanden sein können.

Die folgende Abbildung zeigt mehrere überlappende Ansichten für eine Speicherabbilddatei:

Screenshot that shows views to a memory-mapped file.

Programmieren mit Speicherabbilddateien

Die folgende Tabelle enthält Informationen zur Verwendung von Speicherabbilddatei-Objekten und ihren Membern.

Aufgabe Zu verwendende Methoden oder Eigenschaften
Abrufen eines MemoryMappedFile-Objekts, das eine persistent gespeicherte Speicherabbilddatei darstellt, aus einer Datei auf Datenträger MemoryMappedFile.CreateFromFile -Methode.
Abrufen eines MemoryMappedFile-Objekts, das eine nicht persistent gespeicherte Speicherabbilddatei darstellt (keiner Datei auf Datenträger zugeordnet) MemoryMappedFile.CreateNew -Methode.

- oder -

MemoryMappedFile.CreateOrOpen -Methode.
Abrufen eines MemoryMappedFile-Objekts einer vorhandenen Speicherabbilddatei (persistent gespeichert oder nicht persistent gespeichert) MemoryMappedFile.OpenExisting -Methode.
Abrufen eines UnmanagedMemoryStream-Objekts für eine Ansicht für den sequenziellen Zugriff auf die Speicherabbilddatei MemoryMappedFile.CreateViewStream -Methode.
Zum Abrufen eines UnmanagedMemoryAccessor-Objekts für eine Ansicht für den direkten Zugriff auf die Speicherabbilddatei. MemoryMappedFile.CreateViewAccessor -Methode.
Abrufen eines SafeMemoryMappedViewHandle-Objekts, das mit nicht verwaltetem Code verwendet wird MemoryMappedFile.SafeMemoryMappedFileHandle-Eigenschaft.

- oder -

MemoryMappedViewAccessor.SafeMemoryMappedViewHandle-Eigenschaft.

- oder -

MemoryMappedViewStream.SafeMemoryMappedViewHandle-Eigenschaft.
Verzögern der Speicherbelegung, bis eine Ansicht erstellt wird (nur nicht persistent gespeicherte Dateien)

(Verwenden Sie die Environment.SystemPageSize-Eigenschaft, um die aktuelle Systemseitengröße zu bestimmen.)
Die CreateNew-Methode mit dem MemoryMappedFileOptions.DelayAllocatePages-Wert.

- oder -

CreateOrOpen-Methoden mit einer MemoryMappedFileOptions-Enumeration als Parameter

Sicherheit

Mit den folgenden Methoden, die eine MemoryMappedFileAccess-Enumeration als Parameter akzeptieren, können beim Erstellen einer Speicherabbilddatei Zugriffsrechte angewendet werden:

Sie können mit den OpenExisting-Methoden, die MemoryMappedFileRights als Parameter akzeptieren, Zugriffsrechte für das Öffnen einer vorhandenen Speicherabbilddatei angeben.

Außerdem können Sie ein MemoryMappedFileSecurity-Objekt einschließen, das vordefinierte Zugriffsregeln enthält.

Verwenden Sie die SetAccessControl-Methode, um neue oder geänderte Zugriffsregeln auf eine Speicherabbilddatei anzuwenden. Mit der GetAccessControl-Methode können Zugriffs- oder Überwachungsregeln aus einer vorhandenen Datei abgerufen werden.

Beispiele

Beibehaltene Speicherabbilddateien

Die CreateFromFile-Methoden erstellen eine Speicherabbilddatei aus einer vorhandenen Datei auf einem Datenträger.

Im folgenden Beispiel wird ein Speicherabbild für einen Teil einer sehr großen Datei erstellt und teilweise bearbeitet.

using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;

class Program
{
    static void Main(string[] args)
    {
        long offset = 0x10000000; // 256 megabytes
        long length = 0x20000000; // 512 megabytes

        // Create the memory-mapped file.
        using (var mmf = MemoryMappedFile.CreateFromFile(@"c:\ExtremelyLargeImage.data", FileMode.Open,"ImgA"))
        {
            // Create a random access view, from the 256th megabyte (the offset)
            // to the 768th megabyte (the offset plus length).
            using (var accessor = mmf.CreateViewAccessor(offset, length))
            {
                int colorSize = Marshal.SizeOf(typeof(MyColor));
                MyColor color;

                // Make changes to the view.
                for (long i = 0; i < length; i += colorSize)
                {
                    accessor.Read(i, out color);
                    color.Brighten(10);
                    accessor.Write(i, ref color);
                }
            }
        }
    }
}

public struct MyColor
{
    public short Red;
    public short Green;
    public short Blue;
    public short Alpha;

    // Make the view brighter.
    public void Brighten(short value)
    {
        Red = (short)Math.Min(short.MaxValue, (int)Red + value);
        Green = (short)Math.Min(short.MaxValue, (int)Green + value);
        Blue = (short)Math.Min(short.MaxValue, (int)Blue + value);
        Alpha = (short)Math.Min(short.MaxValue, (int)Alpha + value);
    }
}
Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Runtime.InteropServices

Class Program

    Sub Main()
        Dim offset As Long = &H10000000 ' 256 megabytes
        Dim length As Long = &H20000000 ' 512 megabytes

        ' Create the memory-mapped file.
        Using mmf = MemoryMappedFile.CreateFromFile("c:\ExtremelyLargeImage.data", FileMode.Open, "ImgA")
            ' Create a random access view, from the 256th megabyte (the offset)
            ' to the 768th megabyte (the offset plus length).
            Using accessor = mmf.CreateViewAccessor(offset, length)
                Dim colorSize As Integer = Marshal.SizeOf(GetType(MyColor))
                Dim color As MyColor
                Dim i As Long = 0

                ' Make changes to the view.
                Do While (i < length)
                    accessor.Read(i, color)
                    color.Brighten(10)
                    accessor.Write(i, color)
                    i += colorSize
                Loop
            End Using
        End Using
    End Sub
End Class

Public Structure MyColor
    Public Red As Short
    Public Green As Short
    Public Blue As Short
    Public Alpha As Short

    ' Make the view brighter.
    Public Sub Brighten(ByVal value As Short)
        Red = CType(Math.Min(Short.MaxValue, (CType(Red, Integer) + value)), Short)
        Green = CType(Math.Min(Short.MaxValue, (CType(Green, Integer) + value)), Short)
        Blue = CType(Math.Min(Short.MaxValue, (CType(Blue, Integer) + value)), Short)
        Alpha = CType(Math.Min(Short.MaxValue, (CType(Alpha, Integer) + value)), Short)
    End Sub
End Structure

Im folgenden Beispiel wird die gleiche Speicherabbilddatei für einen anderen Prozess geöffnet.

using System;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;

class Program
{
    static void Main(string[] args)
    {
        // Assumes another process has created the memory-mapped file.
        using (var mmf = MemoryMappedFile.OpenExisting("ImgA"))
        {
            using (var accessor = mmf.CreateViewAccessor(4000000, 2000000))
            {
                int colorSize = Marshal.SizeOf(typeof(MyColor));
                MyColor color;

                // Make changes to the view.
                for (long i = 0; i < 1500000; i += colorSize)
                {
                    accessor.Read(i, out color);
                    color.Brighten(20);
                    accessor.Write(i, ref color);
                }
            }
        }
    }
}

public struct MyColor
{
    public short Red;
    public short Green;
    public short Blue;
    public short Alpha;

    // Make the view brigher.
    public void Brighten(short value)
    {
        Red = (short)Math.Min(short.MaxValue, (int)Red + value);
        Green = (short)Math.Min(short.MaxValue, (int)Green + value);
        Blue = (short)Math.Min(short.MaxValue, (int)Blue + value);
        Alpha = (short)Math.Min(short.MaxValue, (int)Alpha + value);
    }
}
Imports System.IO.MemoryMappedFiles
Imports System.Runtime.InteropServices

Class Program
    Public Shared Sub Main(ByVal args As String())
        ' Assumes another process has created the memory-mapped file.
        Using mmf = MemoryMappedFile.OpenExisting("ImgA")
            Using accessor = mmf.CreateViewAccessor(4000000, 2000000)
                Dim colorSize As Integer = Marshal.SizeOf(GetType(MyColor))
                Dim color As MyColor

                ' Make changes to the view.
                Dim i As Long = 0
                While i < 1500000
                    accessor.Read(i, color)
                    color.Brighten(30)
                    accessor.Write(i, color)
                    i += colorSize
                End While
            End Using
        End Using
    End Sub
End Class

Public Structure MyColor
    Public Red As Short
    Public Green As Short
    Public Blue As Short
    Public Alpha As Short

    ' Make the view brigher.
    Public Sub Brighten(ByVal value As Short)
        Red = CShort(Math.Min(Short.MaxValue, CInt(Red) + value))
        Green = CShort(Math.Min(Short.MaxValue, CInt(Green) + value))
        Blue = CShort(Math.Min(Short.MaxValue, CInt(Blue) + value))
        Alpha = CShort(Math.Min(Short.MaxValue, CInt(Alpha) + value))
    End Sub
End Structure

Nicht beibehaltene Speicherabbilddateien

Die CreateNew-Methode und die CreateOrOpen-Methode erstellen eine Speicherabbilddatei, die keiner vorhandenen Datei auf einem Datenträger zugeordnet ist.

Das folgende Beispiel umfasst drei separate Prozesse (Konsolenanwendungen), die boolesche Werte in eine Speicherabbilddatei schreiben. Die folgende Sequenz von Aktionen wird ausgeführt:

  1. Process A erstellt die Speicherabbilddatei und schreibt in diese einen Wert.

  2. Process B erstellt die Speicherabbilddatei und schreibt in diese einen Wert.

  3. Process C erstellt die Speicherabbilddatei und schreibt in diese einen Wert.

  4. Process A liest die Werte in der Speicherabbilddatei und zeigt diese an.

  5. Nachdem die Bearbeitung der Speicherabbilddatei durch Process A abgeschlossen ist, wird die Datei sofort von der Garbage Collection freigegeben.

Gehen Sie folgendermaßen vor, um dieses Beispiel auszuführen:

  1. Kompilieren Sie die Anwendungen, und öffnen Sie drei Eingabeaufforderungsfenster.

  2. Führen Sie Process A im ersten Eingabeaufforderungsfenster aus.

  3. Führen Sie Process B im zweiten Eingabeaufforderungsfenster aus.

  4. Kehren Sie zu Process A zurück, und drücken Sie die EINGABETASTE.

  5. Führen Sie Process C im dritten Eingabeaufforderungsfenster aus.

  6. Kehren Sie zu Process A zurück, und drücken Sie die EINGABETASTE.

Die Ausgabe von Process A lautet wie folgt:

Start Process B and press ENTER to continue.  
Start Process C and press ENTER to continue.  
Process A says: True  
Process B says: False  
Process C says: True  

Prozess A

using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Threading;

class Program
{
    // Process A:
    static void Main(string[] args)
    {
        using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("testmap", 10000))
        {
            bool mutexCreated;
            Mutex mutex = new Mutex(true, "testmapmutex", out mutexCreated);
            using (MemoryMappedViewStream stream = mmf.CreateViewStream())
            {
                BinaryWriter writer = new BinaryWriter(stream);
                writer.Write(1);
            }
            mutex.ReleaseMutex();

            Console.WriteLine("Start Process B and press ENTER to continue.");
            Console.ReadLine();

            Console.WriteLine("Start Process C and press ENTER to continue.");
            Console.ReadLine();

            mutex.WaitOne();
            using (MemoryMappedViewStream stream = mmf.CreateViewStream())
            {
                BinaryReader reader = new BinaryReader(stream);
                Console.WriteLine("Process A says: {0}", reader.ReadBoolean());
                Console.WriteLine("Process B says: {0}", reader.ReadBoolean());
                Console.WriteLine("Process C says: {0}", reader.ReadBoolean());
            }
            mutex.ReleaseMutex();
        }
    }
}
Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Threading

Module Module1

    ' Process A:
    Sub Main()
        Using mmf As MemoryMappedFile = MemoryMappedFile.CreateNew("testmap", 10000)
            Dim mutexCreated As Boolean
            Dim mTex As Mutex = New Mutex(True, "testmapmutex", mutexCreated)
            Using Stream As MemoryMappedViewStream = mmf.CreateViewStream()
                Dim writer As BinaryWriter = New BinaryWriter(Stream)
                writer.Write(1)
            End Using
            mTex.ReleaseMutex()
            Console.WriteLine("Start Process B and press ENTER to continue.")
            Console.ReadLine()

            Console.WriteLine("Start Process C and press ENTER to continue.")
            Console.ReadLine()

            mTex.WaitOne()
            Using Stream As MemoryMappedViewStream = mmf.CreateViewStream()
                Dim reader As BinaryReader = New BinaryReader(Stream)
                Console.WriteLine("Process A says: {0}", reader.ReadBoolean())
                Console.WriteLine("Process B says: {0}", reader.ReadBoolean())
                Console.WriteLine("Process C says: {0}", reader.ReadBoolean())
            End Using
            mTex.ReleaseMutex()

        End Using

    End Sub

End Module

Prozess B

using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Threading;

class Program
{
    // Process B:
    static void Main(string[] args)
    {
        try
        {
            using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("testmap"))
            {

                Mutex mutex = Mutex.OpenExisting("testmapmutex");
                mutex.WaitOne();

                using (MemoryMappedViewStream stream = mmf.CreateViewStream(1, 0))
                {
                    BinaryWriter writer = new BinaryWriter(stream);
                    writer.Write(0);
                }
                mutex.ReleaseMutex();
            }
        }
        catch (FileNotFoundException)
        {
            Console.WriteLine("Memory-mapped file does not exist. Run Process A first.");
        }
    }
}
Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Threading

Module Module1
    ' Process B:
    Sub Main()
        Try
            Using mmf As MemoryMappedFile = MemoryMappedFile.OpenExisting("testmap")
                Dim mTex As Mutex = Mutex.OpenExisting("testmapmutex")
                mTex.WaitOne()
                Using Stream As MemoryMappedViewStream = mmf.CreateViewStream(1, 0)
                    Dim writer As BinaryWriter = New BinaryWriter(Stream)
                    writer.Write(0)
                End Using
                mTex.ReleaseMutex()
            End Using
        Catch noFile As FileNotFoundException
            Console.WriteLine("Memory-mapped file does not exist. Run Process A first." & vbCrLf & noFile.Message)
        End Try

    End Sub

End Module

Prozess C

using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Threading;

class Program
{
    // Process C:
    static void Main(string[] args)
    {
        try
        {
            using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("testmap"))
            {

                Mutex mutex = Mutex.OpenExisting("testmapmutex");
                mutex.WaitOne();

                using (MemoryMappedViewStream stream = mmf.CreateViewStream(2, 0))
                {
                    BinaryWriter writer = new BinaryWriter(stream);
                    writer.Write(1);
                }
                mutex.ReleaseMutex();
            }
        }
        catch (FileNotFoundException)
        {
            Console.WriteLine("Memory-mapped file does not exist. Run Process A first, then B.");
        }
    }
}
Imports System.IO
Imports System.IO.MemoryMappedFiles
Imports System.Threading

Module Module1
    ' Process C:
    Sub Main()
        Try
            Using mmf As MemoryMappedFile = MemoryMappedFile.OpenExisting("testmap")
                Dim mTex As Mutex = Mutex.OpenExisting("testmapmutex")
                mTex.WaitOne()
                Using Stream As MemoryMappedViewStream = mmf.CreateViewStream(2, 0)
                    Dim writer As BinaryWriter = New BinaryWriter(Stream)
                    writer.Write(1)
                End Using
                mTex.ReleaseMutex()
            End Using
        Catch noFile As FileNotFoundException
            Console.WriteLine("Memory-mapped file does not exist. Run Process A first, then B." & vbCrLf & noFile.Message)
        End Try

    End Sub

End Module

Siehe auch