4

我试图了解应用程序中发生的一个非常奇怪的句柄泄漏。我设法在以下代码中隔离了问题:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication2
{

    public class EventRaiser
    {
        public event EventHandler OnEvent;

        public void DoSomething()
        {
            Console.Write(".");

            try
            {
                throw new Exception("?");
            }
            catch (Exception e)
            {

            }

            if (OnEvent != null)
                OnEvent(this, null);
        }
    }

    public class EventConsumer
    {
        private EventRaiser m_Event;

        public EventConsumer()
        {
            m_Event = new EventRaiser();
            m_Event.OnEvent += m_Event_OnEvent;

        }

        public void Start()
        {
            m_Event.DoSomething();
        }

        private void m_Event_OnEvent(object sender, EventArgs e)
        {
            Task.Run(() => m_Event.DoSomething() ); // 4.5
            //Task.Factory.StartNew(() => m_Event.DoSomething()); // 4.0
        }
    }

    class Program
    {
        private static EventConsumer x;
        static void Main(string[] args)
        {
            x = new EventConsumer();
            x.Start();

            Console.ReadLine();
        }
    }
}

照原样,这个测试应用程序非常非常快地提升到 23721 个句柄(5 秒足以达到这个值)

任务管理器屏幕截图

但是,删除“throw new Exception”行后,应用程序在运行几分钟时保持稳定,大约有 450 个句柄。

知道这里有什么问题吗?

谢谢!

编辑#1

由于问题的警告无法重现,我注意到它仅在 Visual Studio 中以调试模式运行时才会发生(2013 和 2015 Professional 中的结果相同)。

编辑#2

今天,我在另一台使用完全相同版本的 Visual Studio(2013 Pro 12.0.40629.00 Update5)的计算机上测试了完全相同的项目,但这个项目在 Windows 8.1 中运行(我的计算机运行的是 Windows 10),而我是无法在这里重现问题。

编辑#3

我刚刚在另一台运行 Windows 10 和 Visual Studio 2015 Pro 的计算机上进行了测试,再次没有出现问题!现在我非常困惑,因为我在 Visual Studio 2015 Pro 中运行时在我的计算机上遇到了同样的问题,而且我没有安装特殊的扩展。我想我会利用周末来彻底重装系统。

4

1 回答 1

0

由于 .NET 中的关键部分创建行为,可能会发生这种情况。如您所知,该catch块几乎可以保证运行,CLR 创建了一些内部结构来完成这项工作。所以我认为创建了许多句柄是因为这个——你Task在后台运行你的代码,这肯定是一些带有同步的内部结构。

另一方面,当您处于发布模式时,为什么这不是问题?出于调试目的,在没有编译器优化的情况下编译调试模式。发布代码正在优化,你的catch块是空的,所以我认为它永远不会在发布模式下运行——你的代码根本不会抛出,就是这样。

我现在无法检查,但我认为在 Release 中重现问题的方法是在catch块中添加一些代码:

        try
        {
            throw new Exception("?");
        }
        catch (Exception e)
        {
            // log exception here
        }

更新:我认为您测量的句柄数量不是为您的应用程序(ConsoleApplication2.exe),而是为为您创建的 VS 从自身运行()。所以这只是关于.ConsoleApplication2.vshost.exeVisual Studio

于 2015-10-09T06:09:01.000 回答