Condividi tramite


File mappati alla memoria

Un file mappato alla memoria contiene il contenuto di un file nella memoria virtuale. Questo mapping tra un file e uno spazio di memoria consente a un'applicazione, inclusi più processi, di modificare il file leggendo e scrivendo direttamente nella memoria. È possibile usare il codice gestito per accedere ai file mappati alla memoria nello stesso modo in cui le funzioni native di Windows accedono ai file mappati alla memoria, come descritto in Gestione dei file Memory-Mapped.

Esistono due tipi di file mappati alla memoria:

  • File di cui è stato eseguito il mapping permanente alla memoria

    I file persistenti sono file mappati alla memoria associati a un file di origine su un disco. Al termine dell'ultima operazione con il file, i dati vengono salvati nel file di origine sul disco. Questi file mappati alla memoria sono adatti per lavorare con file di origine estremamente grandi.

  • File non persistenti di cui è stato eseguito il mapping alla memoria

    I file non persistenti sono file mappati alla memoria che non sono associati a un file su un disco. Quando l'ultimo processo ha terminato l'uso del file, i dati vengono persi e il file viene recuperato da Garbage Collection. Questi file sono adatti per la creazione di memoria condivisa per le comunicazioni tra processi (IPC).

Processi, viste e gestione della memoria

I file mappati alla memoria possono essere condivisi tra più processi. I processi possono eseguire il mapping allo stesso file mappato alla memoria usando un nome comune assegnato dal processo che ha creato il file.

Per usare un file mappato alla memoria, è necessario creare una visualizzazione dell'intero file mappato alla memoria o una parte di esso. È anche possibile creare più visualizzazioni nella stessa parte del file mappato alla memoria, creando così memoria simultanea. Affinché due visualizzazioni rimangano simultanee, devono essere create dallo stesso file mappato alla memoria.

È anche possibile che siano necessarie più visualizzazioni se il file è maggiore delle dimensioni dello spazio di memoria logico dell'applicazione disponibile per il mapping della memoria (2 GB in un computer a 32 bit).

Esistono due tipi di visualizzazioni: visualizzazione di accesso al flusso e visualizzazione ad accesso casuale. Usare le visualizzazioni di accesso al flusso per l'accesso sequenziale a un file; questa opzione è consigliata per i file non persistenti e IPC. Le visualizzazioni ad accesso casuale sono preferibili per l'uso di file persistenti.

L'accesso ai file mappati alla memoria viene eseguito tramite la gestione della memoria del sistema operativo, quindi il file viene automaticamente partizionato in una serie di pagine e accessibile in base alle esigenze. Non è necessario gestire manualmente la gestione della memoria.

La figura seguente mostra come più processi possono avere più visualizzazioni sovrapposte allo stesso file mappato alla memoria contemporaneamente.

L'immagine seguente mostra più visualizzazioni sovrapposte a un file mappato alla memoria:

Screenshot che mostra le viste di un file mappato in memoria.

Programmazione con file di Memory-Mapped

Nella tabella seguente viene fornita una guida per l'uso di oggetti file mappati alla memoria e dei relativi membri.

Attività Metodi o proprietà da utilizzare
Per ottenere un MemoryMappedFile oggetto che rappresenta un file mappato alla memoria persistente da un file su disco. MemoryMappedFile.CreateFromFile metodo.
Per ottenere un MemoryMappedFile oggetto che rappresenta un file mappato alla memoria non persistente (non associato a un file su disco). MemoryMappedFile.CreateNew metodo.

- o -

MemoryMappedFile.CreateOrOpen metodo.
Per ottenere un oggetto MemoryMappedFile di un file esistente memorizzato nella memoria (persistente o non persistente). MemoryMappedFile.OpenExisting metodo.
Per ottenere un UnmanagedMemoryStream oggetto per una visualizzazione a cui si accede in sequenza al file mappato alla memoria. MemoryMappedFile.CreateViewStream metodo.
Per ottenere un UnmanagedMemoryAccessor oggetto per una visualizzazione ad accesso casuale a un file mappato alla memoria. MemoryMappedFile.CreateViewAccessor metodo.
Per ottenere un SafeMemoryMappedViewHandle oggetto da utilizzare con codice non gestito. La proprietà MemoryMappedFile.SafeMemoryMappedFileHandle.

- o -

La proprietà MemoryMappedViewAccessor.SafeMemoryMappedViewHandle.

- o -

La proprietà MemoryMappedViewStream.SafeMemoryMappedViewHandle.
Per ritardare l'allocazione della memoria fino a quando non viene creata una visualizzazione (solo file non persistenti).

Per determinare le dimensioni correnti della pagina di sistema, utilizzare la Environment.SystemPageSize proprietà .
CreateNew metodo con il MemoryMappedFileOptions.DelayAllocatePages valore .

- o -

CreateOrOpen metodi con un'enumerazione MemoryMappedFileOptions come parametro.

Sicurezza

È possibile applicare i diritti di accesso quando si crea un file mappato alla memoria usando i metodi seguenti che accettano un'enumerazione MemoryMappedFileAccess come parametro:

È possibile specificare i diritti di accesso per l'apertura di un file mappato alla memoria esistente usando i metodi OpenExisting che accettano un MemoryMappedFileRights come parametro.

Inoltre, è possibile includere un MemoryMappedFileSecurity oggetto che contiene regole di accesso predefinite.

Per applicare regole di accesso nuove o modificate a un file mappato alla memoria, usare il SetAccessControl metodo . Per recuperare le regole di accesso o di controllo da un file esistente, usare il GetAccessControl metodo .

Esempi

File Memory-Mapped persistenti

I CreateFromFile metodi creano un file mappato alla memoria da un file esistente su disco.

Nell'esempio seguente viene creata una visualizzazione mappata alla memoria di una parte di un file estremamente grande e ne viene modificata una parte.

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

Nell'esempio seguente viene aperto lo stesso file mappato alla memoria per un altro processo.

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

File di Memory-Mapped non persistenti

I metodi CreateNew e CreateOrOpen creano un file mappato alla memoria che non è associato a un file esistente su disco.

L'esempio seguente è costituito da tre processi separati (applicazioni console) che scrivono valori booleani in un file mappato alla memoria. Si verifica la sequenza di azioni seguente:

  1. Process A crea il file mappato alla memoria e scrive un valore in esso.

  2. Process B apre il file mappato alla memoria e scrive un valore in esso.

  3. Process C apre il file mappato alla memoria e scrive un valore in esso.

  4. Process A legge e visualizza i valori del file mappato alla memoria.

  5. Al Process A termine del file mappato alla memoria, il file viene immediatamente recuperato da Garbage Collection.

Per eseguire questo esempio, eseguire le operazioni seguenti:

  1. Compilare le applicazioni e aprire tre finestre del prompt dei comandi.

  2. Nella prima finestra del prompt dei comandi eseguire Process A.

  3. Nella seconda finestra del prompt dei comandi eseguire Process B.

  4. Tornare a Process A e premere INVIO.

  5. Nella terza finestra del prompt dei comandi eseguire Process C.

  6. Tornare a Process A e premere INVIO.

L'output di Process A è il seguente:

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  

Processo 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

Processo 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

Processo 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

Vedere anche