Condividi tramite


File mappati alla memoria

Un file mappato alla memoria include il contenuto di un file nella memoria virtuale. Questo mapping tra un file e lo spazio di memoria consente a un'applicazione, con più processi, di modificare il file leggendo e scrivendo direttamente nella memoria. A partire da .NET Framework versione 4, è possibile utilizzare 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 nella gestione di file mappati alla memoria in Win32 (la pagina potrebbe essere in inglese) nella libreria MSDN.

Vi sono due tipi di file mappati alla memoria:

  • File mappati alla memoria salvati in modo permanente

    I file persistenti sono file mappati alla memoria associati a un file di origine su un disco. Quando l'utilizzo del file da parte dell'ultimo processo termina, i dati vengono salvati nel file di origine sul disco. Questi file mappati alla memoria sono adatti per l'utilizzo di file di origine di dimensioni molto grandi.

  • File mappati alla memoria non salvati in modo permanente

    I file non persistenti sono file mappati alla memoria non associati a un file di origine su un disco. Quando l'utilizzo del file da parte dell'ultimo processo termina, i dati vengono persi e il file viene recuperato dalla procedura di Garbage Collection. Questi file sono adatti alla creazione di memoria condivisa per le comunicazioni interprocesso (IPC).

Processi, visualizzazioni 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 utilizzando un nome comune assegnato dal processo che ha creato il file.

Per utilizzare un file mappato alla memoria, è necessario creare una vista dell'intero file o di parte di esso. È inoltre possibile creare più viste della stessa parte del file mappato alla memoria, creando in questo modo memoria simultanea. Affinché due viste rimangano simultanee, è necessario che vengano create dallo stesso file mappato alla memoria.

L'utilizzo di più visualizzazioni può essere necessario anche se il file è più grande della dimensione dello spazio in memoria logico dell'applicazione disponibile per il mapping di memoria (2 GB in un computer a 32 bit).

Esistono due tipi di visualizzazioni: visualizzazione di accesso al flusso e visualizzazione di accesso casuale. Utilizzare le visualizzazioni di accesso al flusso per un accesso sequenziale a un file, consigliabile per i file non persistenti e la comunicazione interprocesso (IPC). Le visualizzazioni di accesso casuale sono preferibili per l'utilizzo di file persistenti.

L'accesso ai file mappati alla memoria viene eseguito tramite il gestore della memoria del sistema operativo, pertanto il file viene partizionato automaticamente in un numero di pagine e all'occorrenza viene eseguito l'accesso. Non è necessario gestire manualmente la gestione della memoria.

Nell'illustrazione riportata di seguito viene mostrato come più processi possono disporre di visualizzazioni multiple e sovrapposte contemporaneamente nello stesso file mappato alla memoria.

Visualizzazioni multiple e sovrapposte in un file mappato alla memoria

Visualizzazioni per un file mappato alla memoria

Programmazione con file mappati alla memoria

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

Attività

Metodi o proprietà da utilizzare

Per ottenere un oggetto MemoryMappedFile che rappresenta un file mappato alla memoria persistente da un file su disco.

Metodo MemoryMappedFile.CreateFromFile.

Per ottenere un oggetto MemoryMappedFile che rappresenta un file mappato alla memoria non persistente (non associato a un file su disco).

Metodo MemoryMappedFile.CreateNew.

- oppure -

Metodo MemoryMappedFile.CreateOrOpen.

Per ottenere un oggetto MemoryMappedFile di un file mappato alla memoria esistente (persistente o non persistente).

Metodo MemoryMappedFile.OpenExisting.

Per ottenere un oggetto UnmanagedMemoryStream per una visualizzazione di accesso sequenziale al file mappato alla memoria.

Metodo MemoryMappedFile.CreateViewStream.

Per ottenere un oggetto UnmanagedMemoryAccessor per una visualizzazione di accesso casuale a un file mappato alla memoria.

Metodo MemoryMappedFile.CreateViewAccessor.

Per ottenere un oggetto SafeMemoryMappedViewHandle da utilizzare con codice non gestito.

Proprietà MemoryMappedFile.SafeMemoryMappedFileHandle.

- oppure -

Proprietà MemoryMappedViewAccessor.SafeMemoryMappedViewHandle.

- oppure -

Proprietà MemoryMappedViewStream.SafeMemoryMappedViewHandle.

Per ritardare l'allocazione della memoria fino alla creazione di una visualizzazione (solo file non persistenti)

Per determinare la dimensione corrente di paging del sistema, utilizzare la proprietà Environment.SystemPageSize.

Metodo CreateNew con il valore MemoryMappedFileOptions.DelayAllocatePages.

- oppure -

Metodi CreateOrOpen che dispongono di un'enumerazione MemoryMappedFileOptions come parametro.

Sicurezza

Quando si crea un file mappato alla memoria, è possibile applicare le autorizzazioni di accesso tramite i metodi seguenti che accettano un'enumerazione MemoryMappedFileAccess come parametro:

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

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

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

Esempi

File mappati alla memoria salvati in modo permanente

I metodi CreateFromFile consentono di creare un file mappato alla memoria da un file esistente nel disco.

Nell'esempio seguente viene creata una vista mappata alla memoria di una parte di un file di dimensioni estremamente grandi e ne viene modificata una parte.

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)
                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
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 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);
        }
    }

}

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

Imports System
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
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);
    }
}

File mappati alla memoria non salvati in modo permanente

I metodi CreateNew e CreateOrOpen consentono di creare un file mappato alla memoria non mappato a un file esistente nel disco.

L'esempio seguente è composto 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 tale file.

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

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

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

  5. Dopo che il Process A ha terminato di utilizzare il file mappato alla memoria, il file viene recuperato immediatamente tramite Garbage Collection.

Per eseguire l'esempio, effettuare le operazioni seguenti:

  1. Compilare le applicazioni e aprire tre finestre Prompt dei comandi.

  2. Nella prima finestra Prompt dei comandi, eseguire il Process A.

  3. Nella seconda finestra Prompt dei comandi, eseguire il Process B.

  4. Tornare al Process A e premere INVIO.

  5. Nella terza finestra Prompt dei comandi, eseguire il Process C.

  6. Tornare al 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

Processo A

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
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();
        }
    }
}

Processo B

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
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.");
        }
    }
}

Processo C

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
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.");
        }
    }
}

Vedere anche

Altre risorse

I/O di file e di flussi