在任务

时间:2015-10-08 23:49:43

标签: c# multithreading .net-4.0 .net-4.5 handle-leak

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

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秒足以达到此值)

Task Manager screen shot

但是,删除"抛出新的异常"在运行几分钟时,应用程序保持稳定,有大约450个手柄。

知道这里有什么问题吗?

谢谢!

编辑#1

由于问题的警告不可重现,我发现只有在Visual Studio内部以调试模式运行时才会发生这种情况(2013和2015专业版的结果相同)。

编辑#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中运行时在计算机中遇到了同样的问题而且我没有安装特殊扩展。我想我会用周末来完全重新安装系统。

1 个答案:

答案 0 :(得分:0)

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

从另一方面来看,当你处于发布模式时,为什么这不是一个问题?出于调试目的,正在编译调试模式而不进行编译器优化。发布代码正在优化,您的catch数据块为空,因此我认为它永远不会在发布模式下运行 - 您的代码根本就不会丢弃,而且它就是它

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

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

更新:我认为您正在衡量的不是您的应用程序的句柄数(ConsoleApplication2.exe),而是为您自己创建的VS(ConsoleApplication2 <强> .vshost .exe)。所以这只是关于Visual Studio