Partilhar via


Arquivos mapeados na memória

Um arquivo mapeado na memória contém o conteúdo de um arquivo na memória virtual. Esse mapeamento entre um arquivo e o espaço de memória permite que um aplicativo, incluindo vários processos, modifique o arquivo lendo e gravando diretamente na memória. Você pode usar o código gerenciado para acessar arquivos mapeados na memória da mesma forma que as funções nativas do Windows acessam arquivos mapeados na memória, conforme descrito em Gerenciando arquivos mapeados na memória.

Existem dois tipos de ficheiros mapeados na memória:

  • Arquivos mapeados de memória persistente

    Os arquivos persistentes são arquivos mapeados na memória associados a um arquivo de origem em um disco. Quando o último processo terminar de trabalhar com o arquivo, os dados serão salvos no arquivo de origem no disco. Esses arquivos mapeados na memória são adequados para trabalhar com arquivos de origem extremamente grandes.

  • Arquivos mapeados de memória não persistentes

    Arquivos não persistentes são arquivos mapeados na memória que não estão associados a um arquivo em um disco. Quando o último processo terminar de trabalhar com o arquivo, os dados são perdidos e o arquivo é recuperado pela coleta de lixo. Esses arquivos são adequados para criar memória compartilhada para comunicações entre processos (IPC).

Processos, exibições e gerenciamento de memória

Os arquivos mapeados na memória podem ser compartilhados em vários processos. Os processos podem mapear para o mesmo arquivo mapeado na memória usando um nome comum atribuído pelo processo que criou o arquivo.

Para trabalhar com um arquivo mapeado na memória, você deve criar uma exibição de todo o arquivo mapeado na memória ou parte dele. Você também pode criar várias visualizações para a mesma parte do arquivo mapeado na memória, criando assim memória simultânea. Para que duas vistas permaneçam simultâneas, têm de ser criadas a partir do mesmo ficheiro mapeado na memória.

Várias visualizações também podem ser necessárias se o arquivo for maior do que o tamanho do espaço de memória lógica do aplicativo disponível para mapeamento de memória (2 GB em um computador de 32 bits).

Existem dois tipos de vistas: vista de acesso a fluxo e vista de acesso aleatório. Use visualizações de acesso de fluxo para acesso sequencial a um arquivo; isso é recomendado para arquivos não persistentes e IPC. As visualizações de acesso aleatório são preferidas para trabalhar com arquivos persistentes.

Os arquivos mapeados na memória são acessados através do gerenciador de memória do sistema operacional, de modo que o arquivo é automaticamente particionado em várias páginas e acessado conforme necessário. Você não precisa lidar com o gerenciamento de memória sozinho.

A ilustração a seguir mostra como vários processos podem ter exibições múltiplas e sobrepostas para o mesmo arquivo mapeado na memória ao mesmo tempo.

A imagem a seguir mostra várias exibições sobrepostas para um arquivo mapeado na memória:

Screenshot that shows views to a memory-mapped file.

Programação com arquivos mapeados pela memória

A tabela a seguir fornece um guia para usar objetos de arquivo mapeados na memória e seus membros.

Task Métodos ou propriedades a utilizar
Para obter um MemoryMappedFile objeto que representa um arquivo de memória mapeada persistente de um arquivo no disco. MemoryMappedFile.CreateFromFile método.
Para obter um MemoryMappedFile objeto que representa um arquivo de memória mapeada não persistente (não associado a um arquivo no disco). MemoryMappedFile.CreateNew método.

- ou -

MemoryMappedFile.CreateOrOpen método.
Para obter um MemoryMappedFile objeto de um arquivo de memória mapeada existente (persistente ou não persistente). MemoryMappedFile.OpenExisting método.
Para obter um UnmanagedMemoryStream objeto para uma exibição acessada sequencialmente para o arquivo mapeado na memória. MemoryMappedFile.CreateViewStream método.
Para obter um UnmanagedMemoryAccessor objeto para uma exibição de acesso aleatório a um arquivo mapeado na memória. MemoryMappedFile.CreateViewAccessor método.
Para obter um SafeMemoryMappedViewHandle objeto a ser usado com código não gerenciado. MemoryMappedFile.SafeMemoryMappedFileHandle imóvel.

- ou -

MemoryMappedViewAccessor.SafeMemoryMappedViewHandle imóvel.

- ou -

MemoryMappedViewStream.SafeMemoryMappedViewHandle imóvel.
Para atrasar a alocação de memória até que uma exibição seja criada (somente arquivos não persistentes).

(Para determinar o tamanho atual da página do sistema, use a Environment.SystemPageSize propriedade.)
CreateNew com o MemoryMappedFileOptions.DelayAllocatePages valor.

- ou -

CreateOrOpen métodos que têm uma MemoryMappedFileOptions enumeração como parâmetro.

Segurança

Você pode aplicar direitos de acesso ao criar um arquivo mapeado na memória, usando os seguintes métodos que usam uma MemoryMappedFileAccess enumeração como parâmetro:

Você pode especificar direitos de acesso para abrir um arquivo existente mapeado na memória usando os OpenExisting métodos que tomam um MemoryMappedFileRights como parâmetro.

Além disso, você pode incluir um objeto que contenha regras de MemoryMappedFileSecurity acesso predefinidas.

Para aplicar regras de acesso novas ou alteradas a um arquivo mapeado na memória, use o SetAccessControl método. Para recuperar regras de acesso ou auditoria de um arquivo existente, use o GetAccessControl método.

Exemplos

Arquivos mapeados de memória persistente

Os CreateFromFile métodos criam um arquivo de memória mapeada a partir de um arquivo existente no disco.

O exemplo a seguir cria uma exibição mapeada na memória de uma parte de um arquivo extremamente grande e manipula uma parte dele.

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

O exemplo a seguir abre o mesmo arquivo mapeado na memória para outro 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

Arquivos mapeados de memória não persistentes

Os CreateNew métodos e CreateOrOpen criam um arquivo mapeado na memória que não é mapeado para um arquivo existente no disco.

O exemplo a seguir consiste em três processos separados (aplicativos de console) que gravam valores booleanos em um arquivo mapeado na memória. A seguinte sequência de ações ocorre:

  1. Process A Cria o arquivo mapeado na memória e grava um valor nele.

  2. Process B Abre o arquivo mapeado na memória e grava um valor nele.

  3. Process C Abre o arquivo mapeado na memória e grava um valor nele.

  4. Process A lê e exibe os valores do arquivo mapeado na memória.

  5. Depois de Process A terminar com o arquivo mapeado na memória, o arquivo é imediatamente recuperado pela coleta de lixo.

Para executar este exemplo, faça o seguinte:

  1. Compile os aplicativos e abra três janelas de prompt de comando.

  2. Na primeira janela do prompt de comando, execute Process A.

  3. Na segunda janela do prompt de comando, execute Process B.

  4. Volte para Process A e pressione ENTER.

  5. Na terceira janela do prompt de comando, execute Process C.

  6. Volte para Process A e pressione ENTER.

A saída de é a Process A seguinte:

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: {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

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

Consulte também