Soubory mapované paměti
Soubor mapovaný do paměti obsahuje obsah souboru ve virtuální 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. Spravovaný kód můžete použít pro přístup k souborům mapovaným v paměti stejným způsobem, jakým nativní funkce Systému Windows přistupují k souborům mapovaným v paměti, jak je popsáno v tématu Správa souborů mapovaných pamětí.
Existují dva typy souborů mapovaných do paměti:
Trvalé soubory mapované do paměti
Trvalé soubory jsou soubory mapované do paměti, které jsou přidruženy ke zdrojovému souboru na disku. Po dokončení posledního procesu práce se souborem se data uloží do zdrojového souboru na disku. Tyto soubory mapované do paměti jsou vhodné pro práci s extrémně velkými zdrojovými soubory.
Neudržované soubory mapované do paměti
Neuchované soubory jsou soubory mapované do paměti, které nejsou přidruženy k souboru na disku. Po dokončení posledního procesu práce se souborem dojde ke ztrátě dat a uvolnění souboru uvolněním paměti. Tyto soubory jsou vhodné pro vytvoření sdílené paměti pro komunikaci mezi procesy (IPC).
Procesy, zobrazení a správa paměti
Soubory mapované do paměti je možné sdílet napříč několika procesy. Procesy se můžou mapovat na stejný soubor mapovaný pamětí pomocí běžného názvu, který je přiřazen procesem, který soubor vytvořil.
Pokud chcete pracovat se souborem mapovanými do paměti, musíte vytvořit zobrazení celého souboru mapovaného paměti nebo jeho části. Můžete také vytvořit více zobrazení do stejné části souboru mapovaného paměti, čímž se vytvoří souběžná paměť. Aby dvě zobrazení zůstala souběžná, musí se vytvořit ze stejného souboru mapovaného paměti.
Více zobrazení může být také nutné, pokud je soubor větší než velikost místa logické paměti aplikace dostupného pro mapování paměti (2 GB na 32bitovém počítači).
Existují dva typy zobrazení: zobrazení přístupu ke streamu a zobrazení náhodného přístupu. Použití zobrazení přístupu ke streamu pro sekvenční přístup k souboru; to se doporučuje pro neudržované soubory a IPC. Zobrazení náhodného přístupu jsou upřednostňovaná pro práci s trvalými soubory.
K souborům mapovaným v paměti se přistupuje prostřednictvím správce paměti operačního systému, takže se soubor automaticky rozdělí na několik stránek a podle potřeby se k němu přistupuje. Správu paměti nemusíte zpracovávat sami.
Následující obrázek znázorňuje, jak může mít více procesů více zobrazení a překrývajících se zobrazení do stejného souboru namapovaného na paměť současně.
Následující obrázek ukazuje více zobrazení a překrývajících se zobrazení do souboru mapovaného do paměti:
Programování s mapovanými soubory paměti
Následující tabulka obsahuje průvodce používáním objektů souborů mapovaných v paměti a jejich členů.
Úloha | Metody nebo vlastnosti, které se mají použít |
---|---|
Chcete-li získat MemoryMappedFile objekt, který představuje trvalý soubor mapovaný v paměti ze souboru na disku. | MemoryMappedFile.CreateFromFile Metoda. |
Chcete-li získat MemoryMappedFile objekt, který představuje neuchované soubor mapované paměti (není přidružen k souboru na disku). | MemoryMappedFile.CreateNew Metoda. - nebo - MemoryMappedFile.CreateOrOpen Metoda. |
MemoryMappedFile Získání objektu existujícího souboru mapovaného paměti (trvalé nebo neudržované). | MemoryMappedFile.OpenExisting Metoda. |
Získání objektu UnmanagedMemoryStream pro sekvenční zobrazení k souboru mapovanému paměti. | MemoryMappedFile.CreateViewStream Metoda. |
Získání objektu UnmanagedMemoryAccessor pro náhodné zobrazení přístupu k souboru mapovanému paměti. | MemoryMappedFile.CreateViewAccessor Metoda. |
Získání objektu SafeMemoryMappedViewHandle , který se má použít s nespravovaným kódem. | MemoryMappedFile.SafeMemoryMappedFileHandle Vlastnost. - nebo - MemoryMappedViewAccessor.SafeMemoryMappedViewHandle Vlastnost. - nebo - MemoryMappedViewStream.SafeMemoryMappedViewHandle Vlastnost. |
Odložení přidělování paměti, dokud se nevytvořilo zobrazení (pouze neuchované soubory). (Chcete-li určit aktuální velikost systémové stránky, použijte Environment.SystemPageSize vlastnost.) |
CreateNew metoda s MemoryMappedFileOptions.DelayAllocatePages hodnotou. - nebo - CreateOrOpen metody, které mají MemoryMappedFileOptions výčet jako parametr. |
Zabezpečení
Přístupová práva můžete použít při vytváření souboru mapovaného paměti pomocí následujících metod, které jako parametr berou MemoryMappedFileAccess výčet:
Přístupová práva pro otevření existujícího souboru mapovaného paměti můžete zadat pomocí OpenExisting metod, které jako parametr přebírají MemoryMappedFileRights .
Kromě toho můžete zahrnout MemoryMappedFileSecurity objekt, který obsahuje předdefinovaná pravidla přístupu.
Chcete-li použít nová nebo změněná pravidla přístupu pro soubor mapovaný v paměti, použijte metodu SetAccessControl . Pokud chcete načíst pravidla přístupu nebo auditování z existujícího souboru, použijte metodu GetAccessControl .
Příklady
Trvalé soubory mapované do paměti
Metody CreateFromFile vytvoří soubor mapovaný do paměti z existujícího souboru na disku.
Následující příklad vytvoří zobrazení mapované paměti části extrémně velkého souboru a manipuluje s jeho částí.
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
Následující příklad otevře stejný soubor mapovaný v paměti pro jiný proces.
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
Neudržované soubory mapované do paměti
CreateOrOpen Metody CreateNew vytvoří soubor mapovaný v paměti, který není namapován na existující soubor na disku.
Následující příklad se skládá ze tří samostatných procesů (konzolových aplikací), které zapisují logické hodnoty do souboru mapovaného do paměti. Dochází k následující sekvenci akcí:
Process A
vytvoří soubor mapovaný do paměti a zapíše do něj hodnotu.Process B
otevře soubor mapovaný do paměti a zapíše do něj hodnotu.Process C
otevře soubor mapovaný do paměti a zapíše do něj hodnotu.Process A
přečte a zobrazí hodnoty ze souboru mapovaného paměti.Jakmile
Process A
se soubor mapovaný do paměti dokončí, okamžitě se uvolní uvolňováním paměti.
Pokud chcete tento příklad spustit, postupujte takto:
Zkompilujte aplikace a otevřete tři okna příkazového řádku.
V prvním okně příkazového řádku spusťte
Process A
příkaz .V druhém okně příkazového řádku spusťte
Process B
příkaz .Vraťte se a
Process A
stiskněte ENTER.V třetím okně příkazového řádku spusťte
Process C
příkaz .Vraťte se a
Process A
stiskněte 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
Zpracování 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
Proces 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
Proces 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