Pliki mapowane w pamięci

Plik mapowany na pamięć zawiera zawartość pliku w pamięci wirtualnej. To mapowanie między miejscem na plik i pamięć umożliwia aplikacji, w tym wiele procesów, modyfikowanie pliku przez odczytywanie i zapisywanie bezpośrednio w pamięci. Za pomocą kodu zarządzanego można uzyskać dostęp do plików mapowanych w pamięci w taki sam sposób, jak natywne funkcje systemu Windows uzyskują dostęp do plików mapowanych w pamięci, zgodnie z opisem w temacie Zarządzanie plikami mapowanych pamięci.

Istnieją dwa typy plików mapowanych na pamięć:

  • Utrwalone pliki mapowane na pamięć

    Utrwalone pliki to pliki mapowane w pamięci, które są skojarzone z plikiem źródłowym na dysku. Po zakończeniu ostatniego procesu pracy z plikiem dane są zapisywane w pliku źródłowym na dysku. Te pliki mapowane na pamięć są odpowiednie do pracy z bardzo dużymi plikami źródłowymi.

  • Nietrwałe pliki mapowane na pamięć

    Pliki nietrwałe są mapowane na pamięć, które nie są skojarzone z plikiem na dysku. Gdy ostatni proces zakończy pracę z plikiem, dane zostaną utracone i plik zostanie odzyskany przez odzyskiwanie pamięci. Te pliki są odpowiednie do tworzenia pamięci udostępnionej na potrzeby komunikacji między procesami (IPC).

Procesy, widoki i zarządzanie pamięcią

Pliki mapowane w pamięci mogą być współużytkowane przez wiele procesów. Procesy mogą mapować na ten sam plik mapowany na pamięć przy użyciu nazwy pospolitej przypisanej przez proces, który utworzył plik.

Aby pracować z plikiem mapowanym na pamięć, należy utworzyć widok całego pliku mapowanego na pamięć lub jego część. Można również utworzyć wiele widoków w tej samej części pliku mapowanego na pamięć, tworząc jednocześnie pamięć. Aby dwa widoki pozostały współbieżne, należy je utworzyć na podstawie tego samego pliku mapowanego na pamięć.

Wiele widoków może być również konieczne, jeśli plik jest większy niż rozmiar pamięci logicznej aplikacji dostępnej do mapowania pamięci (2 GB na komputerze 32-bitowym).

Istnieją dwa typy widoków: widok dostępu do strumienia i widok dostępu losowego. Użyj widoków dostępu do strumienia, aby uzyskać dostęp sekwencyjny do pliku; jest to zalecane w przypadku plików nietrwałych i IPC. Widoki dostępu losowego są preferowane do pracy z utrwalone pliki.

Dostęp do plików mapowanych w pamięci jest uzyskiwany za pośrednictwem menedżera pamięci systemu operacyjnego, więc plik jest automatycznie partycjonowany na wiele stron i uzyskiwany do tego dostępu zgodnie z potrzebami. Nie musisz samodzielnie obsługiwać zarządzania pamięcią.

Na poniższej ilustracji pokazano, jak wiele procesów może mieć wiele widoków i nakładających się na siebie widoków do tego samego pliku mapowanego w pamięci w tym samym czasie.

Na poniższej ilustracji przedstawiono wiele i nakładających się widoków do pliku mapowanego na pamięć:

Screenshot that shows views to a memory-mapped file.

Programowanie za pomocą plików mapowanych na pamięć

Poniższa tabela zawiera przewodnik dotyczący używania obiektów plików mapowanych w pamięci i ich elementów członkowskich.

Zadanie Metody lub właściwości do użycia
Aby uzyskać MemoryMappedFile obiekt reprezentujący utrwalonego pliku mapowanego na pamięć z pliku na dysku. MemoryMappedFile.CreateFromFile Metoda.
Aby uzyskać MemoryMappedFile obiekt reprezentujący nietrwały plik mapowany na pamięć (niezwiązany z plikiem na dysku). MemoryMappedFile.CreateNew Metoda.

- lub -

MemoryMappedFile.CreateOrOpen Metoda.
Aby uzyskać MemoryMappedFile obiekt istniejącego pliku mapowanego na pamięć (utrwalone lub nietrwałe). MemoryMappedFile.OpenExisting Metoda.
Aby uzyskać UnmanagedMemoryStream obiekt dla sekwencyjnie dostępnego widoku do pliku mapowanego na pamięć. MemoryMappedFile.CreateViewStream Metoda.
Aby uzyskać UnmanagedMemoryAccessor obiekt dla widoku dostępu losowego do pliku mapowanego na pamięć. MemoryMappedFile.CreateViewAccessor Metoda.
Aby uzyskać SafeMemoryMappedViewHandle obiekt do użycia z kodem niezarządzanym. MemoryMappedFile.SafeMemoryMappedFileHandle Właściwość.

- lub -

MemoryMappedViewAccessor.SafeMemoryMappedViewHandle Właściwość.

- lub -

MemoryMappedViewStream.SafeMemoryMappedViewHandle Właściwość.
Aby opóźnić przydzielanie pamięci do momentu utworzenia widoku (tylko pliki nietrwałe).

(Aby określić bieżący rozmiar strony systemowej, użyj Environment.SystemPageSize właściwości ).
CreateNew metoda z wartością MemoryMappedFileOptions.DelayAllocatePages .

- lub -

CreateOrOpen metody, które mają MemoryMappedFileOptions wyliczenie jako parametr.

Zabezpieczenia

Prawa dostępu można zastosować podczas tworzenia pliku mapowanego w pamięci przy użyciu następujących metod, które przyjmują MemoryMappedFileAccess wyliczenie jako parametr:

Możesz określić prawa dostępu do otwierania istniejącego pliku mapowanego pamięci przy użyciu OpenExisting metod, które przyjmują MemoryMappedFileRights jako parametr.

Ponadto można uwzględnić MemoryMappedFileSecurity obiekt zawierający wstępnie zdefiniowane reguły dostępu.

Aby zastosować nowe lub zmienione reguły dostępu do pliku mapowanego na pamięć, użyj SetAccessControl metody . Aby pobrać reguły dostępu lub inspekcji z istniejącego pliku, użyj GetAccessControl metody .

Przykłady

Utrwalone pliki mapowane na pamięć

Metody CreateFromFile tworzą plik mapowany na pamięć z istniejącego pliku na dysku.

Poniższy przykład tworzy mapowany w pamięci widok części bardzo dużego pliku i manipuluje jego fragmentem.

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

W poniższym przykładzie zostanie otwarty ten sam plik mapowany na pamięć dla innego procesu.

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

Nietrwałe pliki mapowane na pamięć

Metody CreateNew i CreateOrOpen tworzą plik mapowany na pamięć, który nie jest mapowany na istniejący plik na dysku.

Poniższy przykład składa się z trzech oddzielnych procesów (aplikacji konsoli), które zapisują wartości logiczne do pliku mapowanego na pamięć. Następuje następująca sekwencja akcji:

  1. Process A Tworzy plik mapowany na pamięć i zapisuje do niego wartość.

  2. Process B Otwiera plik mapowany na pamięć i zapisuje do niego wartość.

  3. Process C Otwiera plik mapowany na pamięć i zapisuje do niego wartość.

  4. Process A odczytuje i wyświetla wartości z pliku mapowanego w pamięci.

  5. Po Process A zakończeniu pracy z plikiem zamapowanym na pamięć plik jest natychmiast odzyskiwany przez odzyskiwanie pamięci.

Aby uruchomić ten przykład, wykonaj następujące czynności:

  1. Skompiluj aplikacje i otwórz trzy okna wiersza polecenia.

  2. W pierwszym oknie wiersza polecenia uruchom polecenie Process A.

  3. W drugim oknie wiersza polecenia uruchom polecenie Process B.

  4. Wróć do Process A i naciśnij klawisz ENTER.

  5. W trzecim oknie wiersza polecenia uruchom polecenie Process C.

  6. Wróć do Process A i naciśnij klawisz ENTER.

Dane wyjściowe funkcji Process A są następujące:

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  

Proces 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

Proces 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

Proces 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

Zobacz też