Freigeben über


Im Speicher abgebildete Dateien

Eine speicherabbildende Datei enthält den Inhalt einer Datei im virtuellen Speicher. Diese Zuordnung zwischen einer Datei und einem Arbeitsspeicher ermöglicht es einer Anwendung, einschließlich mehrerer Prozesse, die Datei zu ändern, indem sie direkt in den Speicher lesen und schreiben. Sie können verwalteten Code verwenden, um auf Speicher zugeordnete Dateien auf die gleiche Weise zuzugreifen, wie systemeigene Windows-Funktionen auf speicherzuordnungen Dateien zugreifen, wie unter "Verwalten von Memory-Mapped Dateien" beschrieben.

Es gibt zwei Arten von Speicherabbilddateien:

  • Beibehaltene Speicherabbilddateien

    Persistente Dateien sind speicherabbildende Dateien, die mit einer Quelldatei auf einer Festplatte verbunden sind. Wenn der letzte Prozess die Arbeit mit der Datei abgeschlossen hat, werden die Daten in der Quelldatei auf dem Datenträger gespeichert. Diese speicherabbild-Dateien eignen sich für die Arbeit mit extrem großen Quelldateien.

  • Nicht beibehaltene Speicherabbilddateien

    Flüchtige 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 für die Erstellung gemeinsam genutzter Speicher für die Kommunikation zwischen Prozessen (Inter-Process Communications, IPC).

Prozesse, Ansichten und Verwalten von Arbeitsspeicher

Dateien mit Speicherzuordnung können über mehrere Prozesse hinweg freigegeben werden. Prozesse können derselben speicherzuordnungen Datei zugeordnet werden, indem sie einen allgemeinen Namen verwenden, der vom Prozess zugewiesen wird, der die Datei erstellt hat.

Um mit einer speicherzuordnete Datei zu arbeiten, müssen Sie eine Ansicht der gesamten speicherzuordnete Datei 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 die Größe des logischen Speicherplatzes der Anwendung ist, der für die Speicherzuordnung verfügbar ist (2 GB auf einem 32-Bit-Computer).

Es gibt zwei Arten von Ansichten: Streamzugriffsansicht und Zufällige Zugriffsansicht. Verwenden Sie Streamzugriffsansichten für den sequenziellen Zugriff auf eine Datei; Dies wird für nicht persistente Dateien und IPC empfohlen. Zufällige Zugriffsansichten werden zum Arbeiten mit dauerhaften Dateien bevorzugt.

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. Sie müssen die Speicherverwaltung nicht selbst übernehmen.

Die folgende Abbildung zeigt, wie mehrere Prozesse gleichzeitig mehrere und überlappende Ansichten von derselben speicherzugeordneten Datei aufweisen können.

Die folgende Abbildung zeigt mehrere und überlappende Ansichten einer speicherzugeordneten Datei.

Screenshot: Ansichten für eine Speicherabbilddatei

Programmieren mit Memory-Mapped Dateien

Die folgende Tabelle bietet eine Anleitung zur Verwendung von speicherzugeordneten Dateiobjekten und deren Mitglieder.

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.
So rufen Sie ein MemoryMappedFile Objekt ab, das eine nicht persistente Speicherzuordnungsdatei darstellt (nicht mit einer Datei auf dem Datenträger verknüpft). 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.
So rufen Sie ein SafeMemoryMappedViewHandle Objekt ab, das mit nicht verwaltetem Code verwendet werden soll. MemoryMappedFile.SafeMemoryMappedFileHandle-Eigenschaft.

-oder-

MemoryMappedViewAccessor.SafeMemoryMappedViewHandle-Eigenschaft.

-oder-

MemoryMappedViewStream.SafeMemoryMappedViewHandle-Eigenschaft.
So verzögern Sie die Zuweisung des Arbeitsspeichers, bis eine Ansicht erstellt wird (nur nicht persistente Dateien).

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

-oder-

CreateOrOpen Methoden, die eine MemoryMappedFileOptions Enumeration als Parameter aufweisen.

Sicherheit

Sie können Zugriffsrechte anwenden, wenn Sie eine speicherzuordnunge Datei erstellen, indem Sie die folgenden Methoden verwenden, die eine MemoryMappedFileAccess Enumeration als Parameter verwenden:

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

Darüber hinaus 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 speicherzuordnunge Datei anzuwenden. Verwenden Sie die GetAccessControl Methode, um Zugriffs- oder Überwachungsregeln aus einer vorhandenen Datei abzurufen.

Beispiele

Beibehaltene Speicherabbilddateien

Die CreateFromFile Methoden erstellen eine speicherzugeordnete Datei aus einer vorhandenen Datei auf dem Datenträger.

Im folgenden Beispiel wird eine Speicherzuordnungsansicht eines Teils einer extrem großen Datei erstellt und ein Teil davon 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

Das folgende Beispiel öffnet dieselbe speicherzugeordnete Datei für einen anderen Prozess.

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 persistente Memory-Mapped-Dateien

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

Das folgende Beispiel besteht aus drei separaten Prozessen (Konsolenanwendungen), die boolesche Werte in eine speicherzuordnunge Datei schreiben. Die folgende Abfolge von Aktionen tritt auf:

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

  2. Process B öffnet die speicherzuordnungsdatei und schreibt einen Wert hinein.

  3. Process C öffnet die speicherzuordnungsdatei und schreibt einen Wert hinein.

  4. Process A liest und zeigt die Werte aus der speicherabbild-Datei an.

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

Gehen Sie wie folgt vor, um dieses Beispiel auszuführen:

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

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

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

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

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

  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: {reader.ReadBoolean()}");
                Console.WriteLine($"Process B says: {reader.ReadBoolean()}");
                Console.WriteLine($"Process C says: {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