File mappati alla memoria

Un file mappato alla memoria include 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 Windows native accedono ai file mappati alla memoria, come descritto in Gestione di file mappati alla memoria.

Esistono due tipi di file di cui è stato eseguito il mapping alla memoria:

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

    I file persistenti sono file di cui è stato eseguito il mapping alla memoria associati a un file di origine su un disco. Quando l'ultimo processo ha terminato di usare il file, i dati vengono salvati nel file di origine sul disco. Questi file di cui è stato eseguito il mapping alla memoria sono adatti per usare file di origine di dimensioni molto grandi.

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

    I file non persistenti sono file di cui è stato eseguito il mapping alla memoria non associati a un file su un disco. Quando l'ultimo processo ha terminato di usare il file, i dati vanno persi e il file viene recuperato dalla Garbage Collection. Questi file sono adatti per la creazione di memoria condivisa per le comunicazioni interprocesso (IPC).

Processi, visualizzazioni e gestione della memoria

I file di cui è stato eseguito il mapping alla memoria non possono essere condivisi tra più processi. I processi possono eseguire il mapping allo stesso file di cui è stato eseguito il mapping alla memoria usando un nome comune assegnato dal processo che ha creato il file.

Per usare un file di cui è stato eseguito il mapping alla memoria, è necessario creare una visualizzazione dell'intero file di cui è stato eseguito il mapping alla memoria o di una parte. È anche possibile creare più visualizzazioni alla stessa parte del file di cui è stato eseguito il mapping alla memoria, creando quindi una memoria simultanea. Per rimanere simultanee, due visualizzazioni devono essere create dallo stesso file di cui è stato eseguito il mapping alla memoria.

Potrebbero essere necessarie più visualizzazioni anche se le dimensioni del file sono superiori a quelle dello spazio di memoria logica dell'applicazione disponibile per il mapping alla memoria (2 GB in un computer a 32 bit).

Esistono due tipi di visualizzazioni: visualizzazione di accesso a flusso e visualizzazione di accesso casuale. Usare le visualizzazioni di accesso a flusso per l'accesso sequenziale a un file. Questa opzione è consigliata per i file non persistenti e la comunicazione interprocesso. Le visualizzazioni di accesso casuale sono preferibili per l'uso di file persistenti.

I file di cui è stato eseguito il mapping alla memoria sono accessibili tramite il gestore della memoria del sistema operativo, in modo che il file venga automaticamente partizionato in un numero di pagine e sia accessibile se necessario. Non è necessario occuparsi personalmente della gestione della memoria.

La figura seguente illustra come più processi possono avere contemporaneamente più visualizzazioni sovrapposte per lo stesso file di cui è stato eseguito il mapping alla memoria.

L'immagine seguente illustra più visualizzazioni sovrapposte per un file di cui è stato eseguito il mapping alla memoria:

Screenshot that shows views to a memory-mapped file.

Programmazione con i file di cui è stato eseguito il mapping alla memoria

La tabella seguente fornisce una guida all'uso di oggetti di file di cui è stato eseguito il mapping alla memoria e dei relativi membri.

Attività Metodi o proprietà da usare
Ottenere un oggetto MemoryMappedFile che rappresenta un file persistente di cui è stato eseguito il mapping alla memoria da un file su disco. MetodoMemoryMappedFile.CreateFromFile .
Ottenere un oggetto MemoryMappedFile che rappresenta un file non persistente di cui è stato eseguito il mapping alla memoria (non associato a un file su disco). MetodoMemoryMappedFile.CreateNew .

- oppure -

MetodoMemoryMappedFile.CreateOrOpen .
Ottenere un oggetto MemoryMappedFile di un file esistente di cui è stato eseguito il mapping alla memoria (persistente o non persistente). MetodoMemoryMappedFile.OpenExisting .
Ottenere un oggetto UnmanagedMemoryStream per una visualizzazione accessibile in sequenza per il file di cui è stato eseguito il mapping alla memoria. MetodoMemoryMappedFile.CreateViewStream .
Ottenere un oggetto UnmanagedMemoryAccessor per una visualizzazione di accesso casuale per un file di cui è stato eseguito il mapping alla memoria. MetodoMemoryMappedFile.CreateViewAccessor .
Ottenere un oggetto SafeMemoryMappedViewHandle da usare con il codice non gestito. Proprietà MemoryMappedFile.SafeMemoryMappedFileHandle.

- oppure -

Proprietà MemoryMappedViewAccessor.SafeMemoryMappedViewHandle.

- oppure -

Proprietà MemoryMappedViewStream.SafeMemoryMappedViewHandle.
Ritardare l'allocazione della memoria finché non viene creata una visualizzazione (solo file non persistenti).

Per determinare la dimensione di paging del sistema corrente, usare la proprietà Environment.SystemPageSize.
Metodo CreateNew con il valore MemoryMappedFileOptions.DelayAllocatePages.

- oppure -

Metodi CreateOrOpen che hanno un'enumerazione MemoryMappedFileOptions come parametro.

Sicurezza

È possibile applicare i diritti di accesso quando si crea un file di cui è stato eseguito il mapping 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 esistente di cui è stato eseguito il mapping alla memoria usando i metodi OpenExisting che accettano MemoryMappedFileRights come parametro.

È anche possibile includere un oggetto MemoryMappedFileSecurity che contiene le regole di accesso predefinite.

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

Esempi

File persistenti di cui è stato eseguito il mapping alla memoria

I metodi CreateFromFile creano un file di cui viene eseguito il mapping alla memoria da un file esistente su disco.

L'esempio seguente crea una visualizzazione di cui viene eseguito il mapping alla memoria di una parte di un file molto grande e ne modifica 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

L'esempio seguente apre lo stesso file di cui è stato eseguito il mapping 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 non persistenti di cui è stato eseguito il mapping alla memoria

I metodi CreateNew e CreateOrOpen creano un file di cui viene eseguito il mapping alla memoria del quale non viene eseguito il mapping a un file esistente su disco.

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

  1. Process A crea il file di cui viene eseguito il mapping alla memoria e vi scrive un valore.

  2. Process B apre il file di cui è stato eseguito il mapping alla memoria e vi scrive un valore.

  3. Process C apre il file di cui è stato eseguito il mapping alla memoria e vi scrive un valore.

  4. Process A legge e visualizza i valori dal file di cui è stato eseguito il mapping alla memoria.

  5. Dopo che Process A è terminato con il file di cui è stato eseguito il mapping alla memoria, il file viene immediatamente recuperato dalla Garbage Collection.

Per eseguire questo esempio, seguire questa procedura:

  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 è indicato di seguito:

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  

Process 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

Process 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

Process 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

Vedi anche