对象不是垃圾收集

时间:2009-07-08 01:39:28

标签: .net sockets garbage-collection udp

我有一个我正在使用的第三方组件,我看到一些资源未被发布的问题。该组件导致Windows创建UDP套接字的句柄(“\ Device \ Udp”以及“\ Device \ Afd”)。如果我允许程序执行和取消引用第三方对象,我认为就像我过去使用的所有.NET对象一样,该对象将被垃圾收集。但是,Process Explorer显示“\ Device \ Udp”句柄被无限期保留,直到实际进程被终止(或者在有问题的应用程序中:应用程序池被回收。

此外,如果我手动调用对象的Dispose()方法,则释放句柄。这是我已经解决的问题,但我只是想知道为什么需要它。是否有可能组件的构建者已经做了某些事情或设置了一些属性来阻止垃圾收集器调用对象的破坏?

如果有帮助,我已发布以下代码。代码在Forms应用程序中使用,因此在while循环完成后进程不会结束。

无效的代码(无限期创建100个句柄):

        for (int i = 0; i < n; i++)
        {
            Snmpmgr mgr = new Snmpmgr();
            mgr.Timeout = 10;

            mgr.ObjCount = 1;
            mgr.ObjId[1] = ".1.3.6.1.2.1.1.1.0";

            try
            {
                mgr.SendGetRequest();  // Handle shows up in ProcExplorer after this call
            }
            catch (Exception ex)
            {
                throw new TimeoutException("Error contacting CMTS.");
            }
        }  // end of for...  obj referenced by mgr never garbage collected

有效的代码(创建和发布的句柄):

        for (int i = 0; i < n; i++)
        {
            Snmpmgr mgr = new Snmpmgr();
            mgr.Timeout = 10;

            mgr.ObjCount = 1;
            mgr.ObjId[1] = ".1.3.6.1.2.1.1.1.0";

            try
            {
                mgr.SendGetRequest();  // Handle shows up in ProcExplorer after this 
            }
            catch (Exception ex)
            {
                throw new TimeoutException("Error contacting CMTS.");
            }
            mgr.Dispose();  // UDP Socket Handle freed...  not sure that's how to spell free + ed :)
        }

提前感谢您的帮助。

克里斯

5 个答案:

答案 0 :(得分:5)

您在第二个示例中使用了mgr.Dispose调用。我会认为mgr是IDisposable吗?

在这种情况下,您需要使用using块:

for (int i = 0; i < n; i++)
{
    using(Snmpmgr mgr = new Snmpmgr())
    {
        // Your Code
    }
}

答案 1 :(得分:2)

调用Dispose是正确的做法。有些对象使用非托管资源(如果您正在使用套接字,则可能就是这种情况)。 Dispose方法被精确地公开,以便对象可以正确地释放其非托管资源。每次使用实现IDisposable的对象时,都应该在完成后调用Dispose。

有关IDisposable的更多详细信息:How to dispose a class in .net?

答案 2 :(得分:2)

这就是关于Dipose()方法的观点。由于永远不会知道何时调用析构函数,因此应使用Dispose释放非托管资源。 正如MiffTheFox所说,你应该把你的代码放在一个'使用'块中。当代码执行到达'using'块的末尾时,将自动调用Dipose()。

答案 3 :(得分:1)

也许你可以在try / catch块之后将mgr.Dispose()放在你的“finally”子句中。

答案 4 :(得分:0)

确实实际上在Snmpmgr类上实现了一个析构函数来释放套接字句柄,对吗? ...否则GC不知道如果您没有通过Dispose()明确地执行此操作,则需要完成一些工作来释放资源。