Description
Hello,
In my organization, we use MemoryMappedFile extensively.
Because multiple processes might need to access the same MemoryMappedFile concurrently, whenever we need to read data, we:
- Acquire a multi-process lock
- Open the MemoryMappedFile
- Read whatever we need from it, ranging from a few bytes to several megabytes at a time
- Close the MemoryMappedFile
- Release the multi-process lock
We have been experiencing performance issues on this system lately (it is worth noting it has worked OK for years now, but our application keeps growing in use).
When dumping thread stacks, we find quite often that our threads are running the following calls:
System.IO.MemoryMappedFiles!System.IO.MemoryMappedFiles.MemoryMappedView.Flush(unsigned int)
System.IO.MemoryMappedFiles!System.IO.MemoryMappedFiles.MemoryMappedViewAccessor.Dispose(bool)
System.Private.CoreLib!System.IO.UnmanagedMemoryAccessor.Dispose()
our_module!Datalayer.StandardPerfMemoryMappedFile.CloseFile()
out_module!Datalayer.StandardPerfMemoryMappedFile.CloseAndReleaseLock()
When adding log in our module (our_module!Datalayer.StandardPerfMemoryMappedFile.CloseFile()
) we find out that the call to System.IO.UnmanagedMemoryAccessor.Dispose()
is slower than we thought - in the range of ~500ms each.
Given that we didn't perform any write on the MemoryMappedFile (only read), is it correct that the MemoryMappedView flushes on disposal?
Whilst we use this system extensively on all three main OSs (GNU/Linux, Windows, macOS) on .NET 5, we tested this more in-depth in GNU/Linux (Ubuntu 18.04LTS).
Does this issue ring any bells? When a call to the system needs to open several of these files in a row, the performance hit of these Flush calls severely impacts the overall call performance. It is worth noting again that these files are used by a multi-process system, so keeping the files opened and locked by a single process is not an option for us.
Thank you for your help!