1

我正在使用 .NET 中的 Monitor 类,所以我得到了一段似乎可以工作的代码,但是当我循环它一段时间时,它会抛出一个OutOfMemoryException.

我在具有 8 GB RAM 的 64 位 Windows 8 开发人员机器上运行此程序,并且该过程从未占用超过 100 MB 的 RAM 空间。

这是我的代码:

    using System;
    using System.Threading;

    public class Program
    {
        public static void Main()
        {
            while (true) {

                object theLock = new Object();
                Thread threadA = new Thread(() =>
                {
                    Console.WriteLine("Thread A before lock");
                    lock (theLock)
                    {
                        Console.WriteLine("Thread A locking, about to Wait");
                        Monitor.Wait(theLock);
                    }
                    Console.WriteLine("Thread A after lock");
                });

                Thread threadB = new Thread(() =>
                {
                    Console.WriteLine("Thread B before lock");
                    lock (theLock)
                    {
                        Console.WriteLine("Thread B lockint, about to Pulse");
                        Monitor.Pulse(theLock);
                    }
                    Console.WriteLine("Thread B before lock");
                });

                threadA.Start();
                threadB.Start();

                GC.Collect();

            }
        }
    }

我在这里读到这可能是一个碎片问题,我GC.Collect()在最后添加了。但是我没有分配大块的空间。

然后我决定测量循环在抛出异常之前大约经历了多少次迭代并添加了一个计数器:

    using System;
    using System.Threading;

    public class Program
    {
        public static void Main()
        {
            int counter = 0;

            while (true) {
                Console.WriteLine(counter);
                counter++;

                object theLock = new Object();
                Thread threadA = new Thread(() =>
                {
                    Console.WriteLine("Thread A before lock");
                    lock (theLock)
                    {
                        Console.WriteLine("Thread A locking, about to Wait");
                        Monitor.Wait(theLock);
                    }
                    Console.WriteLine("Thread A after lock");
                });

                Thread threadB = new Thread(() =>
                {
                    Console.WriteLine("Thread B before lock");
                    lock (theLock)
                    {
                        Console.WriteLine("Thread B lockint, about to Pulse");
                        Monitor.Pulse(theLock);
                    }
                    Console.WriteLine("Thread B before lock");
                });

                threadA.Start();
                threadB.Start();

                GC.Collect();

            }
        }
    }

这似乎大大减慢了抛出异常的速度。我测量了 36000 次迭代。

4

1 回答 1

4

对于每对线程,如果线程 A 设法在线程 B 之前获得锁,则最终两个线程都会完成,并且可以清理所有内容。

如果线程 B 设法在线程 A 之前获得锁,则线程 B 将完成(已对监视器进行脉冲处理),但随后线程 A 将获取监视器并永远等待某些东西对其进行脉冲处理。因此,那时您将拥有:

  • 一个Thread对象
  • 一个操作系统线程
  • 线程正在等待的对象

...基本上,所有这些都被永远捆绑在一起。

鉴于此,我对您遇到问题并不感到惊讶。

目前尚不清楚您要达到的目标,但这解释了症状。永远不要假设仅仅因为你调用threadA.Start()before threadB.Start(),第一个线程实际上会在第二个线程之前到达代码中的某个点。

于 2015-04-09T14:47:03.683 回答