Freigeben über


Im Speicher abgebildete Dateien

Eine speicherzuordnunge 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 speicherzuordnungen Dateien:

  • Gespeicherte speicherzuordnungen Dateien

    Persisted files are memory-mapped files that are associated with a source file on a disk. Wenn der letzte Prozess die Arbeit mit der Datei abgeschlossen hat, werden die Daten in der Quelldatei auf dem Datenträger gespeichert. Diese speicherzuordnungen Dateien eignen sich für die Arbeit mit extrem großen Quelldateien.

  • Nicht dauerhaft gespeicherte speicherzuordnunge Dateien

    Nicht gespeicherte Dateien sind speicherzuordnungsfähige Dateien, die keiner Datei auf einem Datenträger zugeordnet sind. Wenn der letzte Vorgang die Arbeit mit der Datei abgeschlossen hat, gehen die Daten verloren, und die Datei wird von der Garbage Collection zurückgefordert. 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 speicherzuordnungen Datei zu arbeiten, müssen Sie eine Ansicht der gesamten speicherzuordnungen Datei oder eines Teils davon erstellen. Sie können auch mehrere Ansichten im selben Teil der speicherzuordnungen Datei erstellen, wodurch gleichzeitiger Arbeitsspeicher entsteht. Damit zwei Ansichten gleichzeitig bleiben, müssen sie aus derselben speicherzuordnungen Datei 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.

Auf speicherzuordnunge Dateien wird über den Speicher-Manager des Betriebssystems zugegriffen, sodass die Datei bei Bedarf automatisch in eine Reihe von Seiten partitioniert und auf sie zugegriffen wird. Sie müssen die Speicherverwaltung nicht selbst behandeln.

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

Die folgende Abbildung zeigt mehrere und überlappende Ansichten in einer speicherzuordnungen Datei:

Screenshot, der Ansichten zu einer speicherzuordnungen Datei zeigt.

Programmieren mit Memory-Mapped Dateien

Die folgende Tabelle enthält eine Anleitung für die Verwendung von speicherzuordnungen Dateiobjekten und deren Member.

Aufgabe Zu verwendende Methoden oder Eigenschaften
So rufen Sie ein MemoryMappedFile Objekt ab, das eine gespeicherte Speicherzuordnungsdatei aus einer Datei auf dem Datenträger darstellt. 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.
So rufen Sie ein MemoryMappedFile Objekt einer vorhandenen speicherzuordnungen Datei ab (entweder beibehalten oder nicht beibehalten). MemoryMappedFile.OpenExisting -Methode.
So rufen Sie ein UnmanagedMemoryStream Objekt für eine sequenzielle Ansicht der speicherzuordnungen Datei ab. MemoryMappedFile.CreateViewStream -Methode.
So rufen Sie ein UnmanagedMemoryAccessor Objekt für eine Ansicht mit zufälligem Zugriff auf eine speicherzuordnunge Datei ab. 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 Zugriffsrechte zum Öffnen einer vorhandenen speicherzuordnungen Datei angeben, indem Sie die Methoden verwenden, die OpenExisting einen MemoryMappedFileRights Parameter verwenden.

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

Gespeicherte Memory-Mapped Dateien

Die CreateFromFile Methoden erstellen eine speicherzuordnunge 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

Im folgenden Beispiel wird die gleiche speicherzuordnunge Datei 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 persistente Memory-Mapped-Dateien

Die CreateNew Methoden CreateOrOpen erstellen eine speicherzuordnunge Datei, die keiner vorhandenen Datei auf dem 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 speicherzuordnunge Datei und schreibt einen Wert in die Datei.

  2. Process B öffnet die speicherzuordnunge Datei und schreibt einen Wert in die Datei.

  3. Process C öffnet die speicherzuordnunge Datei und schreibt einen Wert in die Datei.

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

  5. Nach Process A Abschluss der Speicherzuordnungsdatei wird die Datei sofort von der Garbage Collection zurückgefordert.

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 die Ausführung aus Process A.

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

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

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

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

Die Ausgabe lautet Process A 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