Soubory mapované paměti
Obsah souboru virtuální paměti obsahuje soubor mapovaný v paměti. Toto mapování mezi souborem a paměťovým prostorem umožňuje aplikaci, včetně více procesů, upravovat soubor čtením a zápisem přímo do paměti. Začínající .NET Framework verze 4, můžete použít spravovaný kód přístup mapovaný do paměti soubory stejným způsobem jako nativní Windows funkce popsané v přístupu k soubory mapované v paměti Managing Memory-Mapped soubory v systému Win32 v knihovně MSDN.
Existují dva typy souborů mapované paměti:
Trvalé soubory mapované paměti
Trvalé soubory jsou soubory mapované paměti, které jsou přidruženy ke zdrojovému souboru na disku. Když poslední proces dokončí práci se souborem, data jsou uložena do zdrojového souboru na disk. Tyto soubory mapované paměti jsou vhodné pro práci s extrémně velkými zdrojovými soubory.
Netrvalé soubory mapované paměti
Netrvalé soubory jsou soubory mapované paměti, které nejsou přidruženy ke zdrojovému souboru na disku. Po dokončení práce se souborem poslední procesu, dojde ke ztrátě dat a je soubor převzaty systémem pro úklid. Tyto soubory jsou vhodné pro vytváření sdílené paměti pro meziprocesovou komunikaci (IPC).
Procesy, zobrazení a správa paměti
Soubory mapované paměti mohou být sdíleny více procesy. Procesy lze namapovat na stejný soubor mapované paměti použitím běžného názvu, který je přiřazen procesem, který vytvořil soubor.
Chcete-li pracovat se soubor mapované paměti, je nutné vytvořit zobrazení celého souboru mapované paměti nebo jeho části. Můžete také vytvořit více zobrazení do stejné části souboru mapované paměti a tím vytvářit souběžnou paměť. Aby dvě zobrazení zůstaly souběžné, musí být vytvořeny ze stejného souboru mapované paměti.
Více zobrazení může být také nezbytné, pokud je soubor větší než velikost logické paměti aplikace, která je k dispozici pro mapování paměti (2 GB pro 32bitové počítače).
Existují dva typy zobrazení: zobrazení datového proudu a zobrazení s náhodným přístupem. Použijte zobrazení datových proudů pro sekvenční přístup k souboru. Toto je doporučeno pro netrvalé soubory a meziprocesovou komunikaci. Zobrazení s náhodným přístupem jsou upřednostňovány pro práci s trvalými soubory.
K souborům mapované paměti je přistupováno prostřednictvím správce paměti operačního systému tak, aby soubor byl automaticky rozdělen do několika stránek, a aby k němu bylo přístupováno podle potřeby. Nemusíte sami zpracovávat správu paměti.
Následující ilustrace znázorňuje, jak více procesů může mít vícenásobné a překrývající se zobrazení stejného souboru mapované paměti ve stejnou dobu.
Vícenásobné a překrývající se zobrazení souboru mapované v paměti
Programování se soubory mapované paměti
Následující tabulka poskytuje návod pro používání objektů souboru mapované paměti a jejich členů.
Úloha |
Metody nebo vlastnosti pro použití |
---|---|
Pro získání objektu MemoryMappedFile, který představuje trvalý soubor mapované paměti, ze souboru na disku. |
Metoda MemoryMappedFile.CreateFromFile. |
Pro získání objektu MemoryMappedFile, který představuje netrvalý soubor mapované paměti (není přidružen k souboru na disku). |
Metoda MemoryMappedFile.CreateNew. -nebo- Metoda MemoryMappedFile.CreateOrOpen. |
Pro získání objektu MemoryMappedFile existujícího souboru mapované paměti (trvalého nebo netrvalého). |
Metoda MemoryMappedFile.OpenExisting. |
Pro získání objektu UnmanagedMemoryStream pro sekvenční přístup k zobrazení souboru mapované paměti. |
|
Pro získání objektu UnmanagedMemoryAccessor pro náhodný přístup k zobrazení souboru mapované paměti. |
|
Pro získání objektu SafeMemoryMappedViewHandle, který chcete použít s nespravovaným kódem. |
MemoryMappedFile.SafeMemoryMappedFileHandleVlastnost. -nebo- Vlastnost MemoryMappedViewAccessor.SafeMemoryMappedViewHandle. -nebo- |
Pro spoždění přidělování paměti až do vytvoření zobrazení (pouze netrvalé soubory). (Pro určení aktuální velikosti stránky systému, použijte vlastnost Environment.SystemPageSize.) |
Metoda CreateNew s hodnotou MemoryMappedFileOptions.DelayAllocatePages. -nebo- Metody CreateOrOpen, které mají výčet MemoryMappedFileOptions jako parametr. |
Zabezpečení
Můžete použít přístupová práva, když vytvoříte soubor mapované paměti, pomocí následujících metod, které přijímají výčet MemoryMappedFileAccess jako parametr:
Můžete určit přístupová práva pro otevření existujícího souboru mapované paměti použitím metod OpenExisting, které přijmou MemoryMappedFileRights jako parametr.
Kromě toho můžete také zahrnout objekt MemoryMappedFileSecurity, který obsahuje předdefinovaná pravidla přístupu.
Pro použití nových nebo upravených pravidel přístupu k souboru mapované paměti, použijte metodu SetAccessControl. Pro získání pravidel přístupu nebo auditu z existujícího souboru použijte metodu GetAccessControl.
Příklady
Trvalé soubory mapované paměti
Metody CreateFromFile vytvoří soubor mapované paměti z existujícího souboru na disku.
Následující příklad vytvoří zobrazení mapované paměti části extémně velkého souboru a manipuluje s jeho částí.
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);
}
}
}
Následující příklad otevře stejný soubor mapované paměti pro jiný proces.
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);
}
}
Netrvalé soubory mapované paměti
Metody CreateNew a CreateOrOpen vytvoří soubor mapované paměti, který není mapován na existující soubor na disku.
Následující příklad se skládá ze tří oddělených procesů (konzolových aplikací), které zapisují logické hodnoty do souboru mapované paměti. Dojde k následující sekvenci činností:
Process A vytvoří soubor mapované paměti a zapíše do něj hodnotu.
Process B otevře soubor mapované paměti a zapíše do něj hodnotu.
Process C otevře soubor mapované paměti a zapíše do něj hodnotu.
Process A přečte a zobrazí hodnoty ze souboru mapované paměti.
Když Process A ukončí práci se souborem mapované paměti, soubor je okamžitě uvolněn systémem pro uvolnění paměti.
Pro spuštění tohoto příkladu proveďte následující:
Zkompilujte aplikaci a otevřete tři okna Příkazového řádku.
V prvním okně příkazového řádku, spusťte Process A.
Ve druhém okně příkazového řádku spusťte Process B.
Vraťte se do Process A a stiskněte klávesu ENTER.
Ve třetím okně příkazového řádku spusťte Process C.
Vraťte se do Process A a stiskněte klávesu ENTER.
Výstup Process A je následující:
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
Proces 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();
}
}
}
Proces 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.");
}
}
}
Proces 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.");
}
}
}