Jef*_*Cyr 14 .net memory-leaks asynchronous
围绕这个进行了很多讨论,每个人都倾向于同意你应该总是调用Delegate.EndInvoke来防止内存泄漏(甚至Jon Skeet说过它!).
我总是毫不疑问地遵循这个准则,但最近我实现了自己的AsyncResult类,并发现可能泄漏的唯一资源是AsyncWaitHandle.
(事实上它并没有真正泄漏,因为WaitHandle使用的本机资源被封装在一个具有Finalizer的SafeHandle中,但它会对垃圾收集器的finalize队列施加压力.即便如此,AsyncResult的良好实现也会只按需初始化AsyncWaitHandle ...)
了解是否存在泄漏的最佳方法就是尝试:
Action a = delegate { };
while (true)
    a.BeginInvoke(null, null);
我运行了一段时间,内存保持在9-20 MB之间.
让我们与调用Delegate.EndInvoke时进行比较:
Action a = delegate { };
while (true)
    a.BeginInvoke(ar => a.EndInvoke(ar), null);
通过这个测试,内存在9-30 MG之间播放,怪异的呃?(可能是因为当存在AsyncCallback时执行需要更长的时间,因此ThreadPool中将有更多的排队委托)
你觉得怎么样......"神话被破坏了"?
PS ThreadPool.QueueUserWorkItem比Delegate.BeginInvoke效率高一百,它更适合用于fire&forget调用.
Eri*_*sch 11
它当前是否泄漏内存不是你应该依赖的东西.未来,框架团队可能会以一种可能导致泄密的方式改变事物,而且由于官方政策是"你必须调用EndInvoke",那么它就是"按设计".
你是否真的希望你的应用程序在未来的某个时间突然开始泄漏内存,因为你选择依靠观察到的行为而不是记录的要求?
我做了一个小测试来调用一个Action委托并在其中抛出一个异常.然后我确保通过仅维护一次运行的指定数量的线程并且在删除调用结束时连续填充线程池来确保我不会泛洪线程池.这是代码:
static void Main(string[] args)
{
    const int width = 2;
    int currentWidth = 0;
    int totalCalls = 0;
    Action acc = () =>
    {
        try
        {
            Interlocked.Increment(ref totalCalls);
            Interlocked.Increment(ref currentWidth);
            throw new InvalidCastException("test Exception");
        }
        finally
        {
            Interlocked.Decrement(ref currentWidth);
        }
    };
    while (true)
    {
        if (currentWidth < width)
        {
            for(int i=0;i<width;i++)
                acc.BeginInvoke(null, null);
        }
        if (totalCalls % 1000 == 0)
            Console.WriteLine("called {0:N}", totalCalls);
    }
}
让它运行大约20分钟后,超过3000万个BeginInvoke调用以后私有字节内存消耗是恒定的(23 MB)以及句柄计数.似乎没有泄漏存在.我已经通过CLR阅读了Jeffry Richters的C#书,其中他说存在内存泄漏.对于.NET 3.5 SP1,至少这似乎不再适用.
测试环境:Windows 7 x86 .NET 3.5 SP1 Intel 6600双核2.4 GHz
你的,Alois Kraus
| 归档时间: | 
 | 
| 查看次数: | 2822 次 | 
| 最近记录: |