出于某种原因,当我从内存映射文件中读取几次它只是从内存中随机删除时,我不知道发生了什么。内核或GC是否从内存中删除它?如果是,我如何阻止他们这样做?
我正在将一个对象序列化为Json并将其写入内存。
几次尝试再次阅读时,我得到一个例外,我得到了FileNotFoundException: Unable to find the specified file.
private const String Protocol = @"Global\";
public static Boolean WriteToMemoryFile<T>(List<T> data)
{
try
{
if (data == null)
{
throw new ArgumentNullException("Data cannot be null", "data");
}
var mapName = typeof(T).FullName.ToLower();
var mutexName = Protocol + typeof(T).FullName.ToLower();
var serializedData = JsonConvert.SerializeObject(data);
var capacity = serializedData.Length + 1;
var mmf = MemoryMappedFile.CreateOrOpen(mapName, capacity);
var isMutexCreated = false;
var mutex = new Mutex(true, mutexName, out isMutexCreated);
if (!isMutexCreated)
{
var isMutexOpen = false;
do
{
isMutexOpen = mutex.WaitOne();
}
while (!isMutexOpen);
var streamWriter = new StreamWriter(mmf.CreateViewStream());
streamWriter.WriteLine(serializedData);
streamWriter.Close();
mutex.ReleaseMutex();
}
else
{
var streamWriter = new StreamWriter(mmf.CreateViewStream());
streamWriter.WriteLine(serializedData);
streamWriter.Close();
mutex.ReleaseMutex();
}
return true;
}
catch (Exception ex)
{
return false;
}
}
public static List<T> ReadFromMemoryFile<T>()
{
try
{
var mapName = typeof(T).FullName.ToLower();
var mutexName = Protocol + typeof(T).FullName.ToLower();
var mmf = MemoryMappedFile.OpenExisting(mapName);
var mutex = Mutex.OpenExisting(mutexName);
var isMutexOpen = false;
do
{
isMutexOpen = mutex.WaitOne();
}
while (!isMutexOpen);
var streamReader = new StreamReader(mmf.CreateViewStream());
var serializedData = streamReader.ReadLine();
streamReader.Close();
mutex.ReleaseMutex();
var data = JsonConvert.DeserializeObject<List<T>>(serializedData);
mmf.Dispose();
return data;
}
catch (Exception ex)
{
return default(List<T>);
}
}
创建内存映射文件的进程必须保留对它的引用,只要您希望它存在。正是由于这个原因,使用CreateOrOpen
有点棘手 - 你不知道处理内存映射文件是否会破坏它。
你可以通过在mmf.Dispose()
方法中添加一个明确的WriteToMemoryFile
来轻松地看到它 - 它将完全关闭文件。 Dispose
方法从mmf
实例的终结器调用一段时间后,所有引用都退出了范围。
或者,为了使GC更加明显是罪魁祸首,您可以尝试显式调用GC:
WriteToMemoryFile("Hi");
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
ReadFromMemoryFile().Dump(); // Nope, the value is lost now
请注意,我稍微改变了您的方法以使用简单的字符串;你真的想要生成最简单的代码来重现你观察到的行为。即使只是得到JsonConverter
是一个不必要的复杂,可能会导致人们甚至没有尝试运行你的代码:)
作为旁注,你想在你做AbandonedMutexException
时检查Mutex.WaitOne
- 这不是失败,它意味着你接管了互斥锁。大多数应用程序处理这个错误,导致死锁以及互斥锁所有权和生命周期问题:)换句话说,将AbandonedMutexException
视为成功。哦,将Mutex.ReleaseMutex
这样的东西放在finally
子句中是个好主意,以确保它确实发生,即使你得到一个例外。线程或进程死不重要(这只会导致其他一个参与者获得AbandonedMutexException
),但是如果你得到一个你用return false;
“处理”的异常,那么在你关闭所有你的mutex之前不会释放互斥锁应用程序,重新开始:)
显然,问题是MMF失去了Luaan解释的背景。但仍然没有人解释如何执行它:
因此,只要从第二部分读取MMF文件,运行“写入MMF文件”的异步线程就会运行。因此,我们创建了内存映射文件有效的上下文。