The memory file is deleted from memory.

For some reason, when I read from a memory mapped file a couple of times, it just accidentally gets deleted from memory, I don’t know what is going on. Does the kernel or GC delete it from memory? If so, how do I prevent them?

I serialize a Json object and write it to memory.

I get an exception when I try to read again a couple of times, I get a FileNotFoundException: Unable to find the specified file.

 private const String Protocol = @"Global\"; 

Code for writing to a memory mapping file:

 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; } } 

Code for reading from a memory mapped file:

 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>); } } 
+7
source share
2 answers

The process that created the memory mapped file should contain a link to it as long as you want it to live. Using CreateOrOpen bit complicated for this purpose - you do not know if you are going to destroy a file with memory mapping or not.

You can easily see this at work by adding explicit mmf.Dispose() to your WriteToMemoryFile method - it will completely close the file. The Dispose method is called from the finalizer of the mmf instance some time after all references to it fall out of scope.

Or, to make it even more obvious that the GC is the culprit, you can try explicitly invoking the GC:

 WriteToMemoryFile("Hi"); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); ReadFromMemoryFile().Dump(); // Nope, the value is lost now 

Note that I slightly modified the methods to work with simple strings; you really want to create the simplest possible code that reproduces the behavior you observe. Even just getting JsonConverter is an unnecessary complication and might make people not even try to run your code :)

And as a side note, you want to Mutex.WaitOne AbandonedMutexException when you make a Mutex.WaitOne - this is not a failure, so you took the mutex. Most applications handle this incorrectly, which leads to deadlock issues, as well as ownership of the mutex and life cycle :) In other words, treat AbandonedMutexException as a success. Oh, and it's a good idea to put things like Mutex.ReleaseMutex in a finally clause to make sure that this really happens, even if you get an exception. The thread or the process of the dead does not matter (this will simply cause one of the other participants to get an AbandonedMutexException ), but if you just get an exception that you are β€œhandling” with your return false; , the mutex will not be released until you close all your applications and start fresh again :)

+3
source

Obviously, the problem is that the MMF is losing its context, as Luaan explained. But still no one explains how to do this:

  1. The "Write to MMF file" code must run in a separate asynchronous thread.
  2. The Read from MMF code will notify you after reading that the MMF has been read. A notification can be a flag in a file, for example.

Therefore, the asynchronous stream performing "Write to MMF file" will work as long as the MMF file is read from the second part. Therefore, we created a context in which the memory file is displayed.

0
source

Source: https://habr.com/ru/post/986278/


All Articles