Arquivos mapeados na memória
Um arquivo mapeado para memória contém o conteúdo de um arquivo de memória virtual. Esse mapeamento entre um espaço de memória e arquivo permite que um aplicativo, incluindo vários processos modificar o arquivo, ler e gravar diretamente para a memória. Começando com o .NET Framework versão 4, você pode usar código gerenciado para acessar arquivos mapeados na memória, da mesma forma que as funções nativas do Windows acessar arquivos mapeados na memória, conforme descrito em Managing Memory-Mapped de arquivos no Win32 em que o Biblioteca MSDN.
Há dois tipos de arquivos mapeados na memória:
Arquivos de memória mapeada persistentes
Persistentes são arquivos mapeados na memória que estão associados um arquivo de origem em um disco. Quando o último processo tiver terminado de trabalhar com o arquivo, os dados são salvos no arquivo de origem no disco. Esses arquivos de memória mapeada são adequados para trabalhar com arquivos de origem extremamente grandes.
Arquivos de memória mapeada não persistente
Não-persistentes são mapeados para memória arquivos que não estão associados um arquivo em um disco. Quando o último processo tiver terminado 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ção entre processos (IPC).
Processos, exibições e gerenciamento de memória
Arquivos mapeados na memória podem ser compartilhados entre vários processos. Processos podem mapear para o mesmo arquivo de memória mapeada usando um nome comum que é atribuído pelo processo que criou o arquivo.
Para trabalhar com um arquivo de memória mapeada, você deve criar uma exibição de todo o arquivo de memória mapeada ou parte dela. Você também pode criar vários modos de exibição para a mesma parte do arquivo de memória mapeada, criando assim simultâneas de memória. Dois modos de exibição permanecer simultâneas, precisam ser criados a partir do mesmo arquivo de memória mapeada.
Vários modos de exibição também podem ser necessários se o arquivo for maior que o tamanho do espaço de memória lógica do aplicativo disponível para mapeamento (2 GB em um computador de 32 bits) de memória.
Há dois tipos de modos: modo de acesso de fluxo e o modo de acesso aleatório. Usar exibições de acesso de fluxo de acesso seqüencial a um arquivo; Isso é recomendado para arquivos não-persistentes e IPC. Modos de exibição de acesso aleatório são preferenciais para trabalhar com arquivos persistentes.
Arquivos mapeados na memória são acessados através do Gerenciador de memória do sistema operacional, para que o arquivo automaticamente é particionado em um número de páginas e acessado conforme necessário. Você não tem de lidar com o gerenciamento de memória por conta própria.
A ilustração a seguir mostra como vários processos podem ter vários e sobreposição de modos de exibição para o mesmo arquivo de memória mapeada ao mesmo tempo.
Vários e sobrepostos de modos de exibição para um arquivo de memória mapeada
Programação com arquivos mapeados na memória
A tabela a seguir fornece um guia para usar o arquivo mapeado para memória de objetos e seus membros.
Tarefa |
Métodos ou propriedades para usar |
---|---|
Para obter um MemoryMappedFile objeto que representa um arquivo de mapeamento de memória persistente de um arquivo em disco. |
|
Para obter um MemoryMappedFile objeto representando um não-persistentes arquivo mapeado para memória (não associado com um arquivo no disco). |
MemoryMappedFile.CreateNewmétodo. - ou - |
Para obter um MemoryMappedFile o objeto de um mapeamento de memória arquivo existente (persistente ou não-persistentes). |
|
Para obter um UnmanagedMemoryStream o objeto para um modo de exibição acessado seqüencialmente no arquivo memória mapeada. |
|
Para obter um UnmanagedMemoryAccessor de objeto para um modo de exibição de acesso aleatório uma memória mapeada po. |
|
Para obter um SafeMemoryMappedViewHandle o objeto para usar com o código não gerenciado. |
MemoryMappedFile.SafeMemoryMappedFileHandlepropriedade. - ou - MemoryMappedViewAccessor.SafeMemoryMappedViewHandlepropriedade. - ou - MemoryMappedViewStream.SafeMemoryMappedViewHandlepropriedade. |
Atrasar a alocação de memória até que um modo de exibição é criado (somente arquivos não-persistentes). (Para determinar o tamanho da página atual do sistema, use o Environment.SystemPageSize propriedade.) |
CreateNewmétodo com o MemoryMappedFileOptions.DelayAllocatePages valor. - ou - CreateOrOpenos métodos que possuem um MemoryMappedFileOptions enumeração como um parâmetro. |
Segurança
Você pode aplicar direitos de acesso quando você cria um arquivo de memória mapeada, usando os métodos a seguir levam uma MemoryMappedFileAccess enumeração como um parâmetro:
Você pode especificar os direitos de acesso para abrir um arquivo de memória mapeada existente usando o OpenExisting métodos levam uma MemoryMappedFileRights como um parâmetro.
Além disso, você pode incluir um MemoryMappedFileSecurity objeto que contém as regras de acesso predefinidos.
Para aplicar regras de acesso de novos ou alterados em um arquivo de memória mapeada, use o SetAccessControl método. Para recuperar o acesso ou auditoria regras de um arquivo existente, use o GetAccessControl método.
Exemplos
Arquivos de memória mapeada persistentes
O 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 de memória mapeada de uma parte de um arquivo muito grande e manipula uma parte dele.
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);
}
}
}
O exemplo a seguir abre o mesmo arquivo de memória mapeada para outro 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);
}
}
Arquivos de memória mapeada não persistentes.
O CreateNew e CreateOrOpen métodos criam um arquivo de memória mapeada que não está mapeado para um arquivo existente no disco.
O exemplo a seguir consiste em três processos separados (aplicativos de console) que gravar valores booleanos para um arquivo de memória mapeada. A seguinte seqüência de ações ocorrem:
Process Acria o arquivo de memória mapeada e grava um valor.
Process BAbre o arquivo de memória mapeada e grava um valor.
Process CAbre o arquivo de memória mapeada e grava um valor.
Process Alê e exibe os valores do arquivo de memória mapeada.
Depois de Process A é concluído com o arquivo de memória mapeada, o arquivo é imediatamente recuperado pela coleta de lixo.
Para executar esse exemplo, faça o seguinte:
Compilar os aplicativos e abrir três janelas de Prompt de comando.
Na primeira janela do Prompt de comando, execute o Process A.
Na segunda janela do Prompt de comando, execute o Process B.
Retorno para Process A e pressione ENTER.
Na terceira janela de Prompt de comando, execute o Process C.
Retorno para Process A e pressione ENTER.
A saída de Process A é o 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
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.");
}
}
}