内存映射文件从内存中删除

Nik*_*vic 7 c# memory mutex

出于某种原因,当我从内存映射文件中读取几次它只是从内存中随机删除时,我不知道发生了什么.内核或GC是否从内存中删除它?如果是,我如何阻止他们这样做?

我正在将一个对象序列化为Json并将其写入内存.

几次尝试再读一次后,我得到一个例外,我得到了 FileNotFoundException: Unable to find the specified file.

private const String Protocol = @"Global\";
Run Code Online (Sandbox Code Playgroud)

写入内存映射文件的代码:

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;
            }
        }
Run Code Online (Sandbox Code Playgroud)

从内存映射文件中读取的代码:

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

        }
Run Code Online (Sandbox Code Playgroud)

Lua*_*aan 4

只要您希望内存映射文件存在,创建内存映射文件的进程就必须保留对它的引用。正是由于这个原因,使用起来CreateOrOpen有点棘手 - 您不知道处理内存映射文件是否会破坏它。

mmf.Dispose()通过向您的方法添加显式内容,您可以轻松地看到这一点WriteToMemoryFile- 它将完全关闭文件。在对实例的所有引用都超出范围后的某个时间,该Dispose方法会从实例的终结器调用。mmf

或者,为了更明显地看出 GC 是罪魁祸首,您可以尝试显式调用 GC:

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

请注意,我稍微更改了您的方法以处理简单的字符串;您确实希望生成尽可能简单的代码来重现您观察到的行为。即使只是必须获取JsonConverter也是不必要的复杂化,并且可能会导致人们甚至不尝试运行您的代码:)

作为旁注,您需要检查AbandonedMutexException您何时执行操作Mutex.WaitOne- 这不是失败,这意味着您接管了互斥体。大多数应用程序都会错误地处理此问题,从而导致死锁以及互斥锁所有权和生命周期问题:) 换句话说,AbandonedMutexException视为成功。哦,最好将诸如此类的内容放在子句Mutex.ReleaseMutexfinally,以确保它确实发生,即使您遇到例外。线程或进程死亡并不重要(这只会导致其他竞争者之一获得AbandonedMutexException),但是如果您只是得到一个用您的“处理”的异常return false;,则互斥锁将不会被释放,直到您关闭所有应用程序并且重新开始:)