我使用MemoryMappedFile在两个进程之间交换数据。所以我在这两个过程中创建/打开了这样的文件:
private readonly MemoryMappedFile m_MemoryMappedFile = MemoryMappedFile.CreateOrOpen("Demo", 8);
文件访问本身在两个进程中都使用全局互斥锁进行保护。现在,当我向文件写入大于定义的8字节长度的数据时, NOT 会出现异常。
var random = new Random();
var testData = new byte[55];
random.NextBytes(testData);
using (var contentAccessor = m_MemoryMappedFile.CreateViewStream())
{
contentAccessor.Write(testData, 0, testData.Length);
}
所以也许我在这里弄错了,但我想如果我创建一个具有指定容量的非持久内存映射文件(在我的情况下为8个字节),则不允许写入超过8个字节的更多数据?或者我通过上面的电话破坏了记忆?任何解释都会很棒吗?
干杯, 弗朗兹
答案 0 :(得分:1)
在MSDN文章中特别提到了CreateViewStream():
要创建内存映射文件的完整视图,请为size参数指定0(零)。如果这样做,视图的大小可能小于或大于磁盘上源文件的大小。这是因为视图以系统页面为单位提供,并且视图的大小向上舍入到下一个系统页面大小。
哪个有小错误,它不小。确实向上舍入到页面大小。最好的办法是使用方法重载来设置视图大小:
using (var contentAccessor = m_MemoryMappedFile.CreateViewStream(0, 8))
{
contentAccessor.Write(testData, 0, testData.Length);
}
答案 1 :(得分:0)
tl;dr:是的 - C# MemoryMappedFile
会扩展 - 但只会扩展到 Environment.SystemPageSize
的下一个最大倍数(typically 4,096 字节)。一旦它的大小超过该倍数,就会抛出异常。
我遇到这个问题是因为我正在研究如何使用 MemoryMappedFile
来绕过 MemoryStream
(其支持字段 is a byte array)仅限于 int.MaxValue
价值。
我看到了与您在可以超出指定容量写入/读取数据时所做的相同行为,并注意到 the documentation for MemoryMappedFile.CreateOrOpen(string mapName, long capacity)
明确表示(强调我的):
capacity
分配给内存映射文件的最大大小(以字节为单位)。
这显然与我们所看到的不符。
作为 Hans Passant points out,视图流的大小实际上是 Environment.SystemPageSize
的倍数,根据 the Wikipedia page for Page Size 传统上的固定值是 4,096 字节。< /p>
您可以通过检查 MemoryMappedViewStream
上的一些属性来确认这一点,例如:
var pageSize = Environment.SystemPageSize;
Console.WriteLine($"System page size: {pageSize} bytes");
Console.WriteLine();
var capacity = 1;
Console.WriteLine($"Creating MemoryMappedFile with capacity of {capacity} byte(s)");
using ( var memoryMappedFile = MemoryMappedFile.CreateOrOpen("Demo", capacity) )
using ( var viewStream = memoryMappedFile.CreateViewStream() )
{
Console.WriteLine($"View stream capacity: {viewStream.Capacity} bytes");
Console.WriteLine($"View stream length: {viewStream.Length} bytes");
Console.WriteLine();
var randomBytes = new byte[pageSize];
new Random().NextBytes(randomBytes);
viewStream.Write(randomBytes, offset: 0, count: randomBytes.Length);
Console.WriteLine($"{randomBytes.Length} bytes written to view stream");
viewStream.Position = 0;
for ( int index = 0; index < randomBytes.Length; index++ )
{
var writtenByte = randomBytes[index];
var readByte = viewStream.ReadByte();
if ( readByte != writtenByte )
throw new Exception($"Read byte at index {index} ({readByte}) was not the same as written ({writtenByte})");
}
Console.WriteLine($"{randomBytes.Length} bytes successfully read and verified from view stream");
Console.WriteLine();
// Attempt to write another byte (this should throw a NotSupportedException )
try
{
viewStream.WriteByte(0);
throw new InvalidOperationException("An extra byte was written to the view stream when it should not have");
}
catch ( NotSupportedException ex )
{
Console.WriteLine($"Unable to write additional bytes to view stream:{Environment.NewLine} {ex.Message}");
}
}
输出:
System page size: 4096 bytes
Creating MemoryMappedFile with capacity of 1 byte(s)
View stream capacity: 4096 bytes
View stream length: 4096 bytes
4096 bytes written to view stream
4096 bytes successfully read and verified from view stream
Unable to write additional bytes to view stream:
Unable to expand length of this stream beyond its capacity.
注意:C# System.IO.MemoryMappedFiles
namespace 中的类型是 Windows API 调用的有效 C# 包装器,例如CreateFileMappingW
和 OpenFileMappingW
,Microsoft 文档中有大量相关文档。
例如,在 Creating a File Mapping Object 上它说(强调我的):
<块引用>文件映射对象的大小与被映射文件的大小无关。但是,如果文件映射对象大于文件,系统会在 CreateFileMapping
返回之前扩展文件。如果文件映射对象小于文件,则系统只从文件中映射指定的字节数。
CreateFileMapping
的 dwMaximumSizeHigh 和 dwMaximumSizeLow 参数允许您指定要从文件映射的字节数:
CreateFileMapping
并为 dwMaximumSizeHigh 和 指定零dwMaximumSizeLow。这样做会创建一个与文件大小完全相同的文件映射对象。 否则,由于文件映射对象的大小是静态的,您必须计算或估计完成的文件的大小;一旦创建,它们的大小就不能增加或减少。在 Managing Memory-Mapped Files 上说:
<块引用>使用 MMF I/O 的一个优势是系统在 4K 页的数据中为其执行所有数据传输。
这同意 the documentation for MemoryMappedFile.CreateViewStream
说(强调我的):
要创建内存映射文件的完整视图,请为 size
参数指定 0(零)。如果这样做,视图的大小可能会大于磁盘上源文件的大小。这是因为视图是以系统页面为单位提供的,并且视图的大小四舍五入到下一个系统页面大小。
换句话说,作为 MemoryMappedFile
的实现细节(即它是 Windows API 调用的包装器),传递给静态构造函数的 capacity
有效地四舍五入到下一个最大的倍数系统页面大小,因为虚拟地址空间被拆分为页面(typically 4,096 字节)。
相关问题: