码迷,mamicode.com
首页 > 其他好文 > 详细

SocketAsyncEventArgs的释放问题

时间:2014-06-11 09:23:15      阅读:634      评论:0      收藏:0      [点我收藏+]

标签:style   class   blog   code   java   http   

起因是发现一个同事编写的程序运行两个月左右,占用了服务器20G左右的内存。用WinDbg查看发现存在大量的Async Pinned Handles,而它们的gcroot都来自于SocketAsyncEventArgs。下面是场景的简易模拟代码(为了说明问题添加了手动GC):

bubuko.com,布布扣
for (var i = 0; i < 1000; ++i)
{
    var endPoint = new IPEndPoint(IPAddress.Parse(host), port);
    var socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
    socket.ReceiveBufferSize = bufferSize;
    socket.SendBufferSize = bufferSize;

    var iocp = new SocketAsyncEventArgs();
    iocp.Completed += new EventHandler<SocketAsyncEventArgs>(OnIoSocketCompleted);
    iocp.SetBuffer(new Byte[bufferSize], 0, bufferSize);
    iocp.AcceptSocket = socket;

    try
    {
        socket.Connect(endPoint);
        Console.WriteLine(i);
    }
    catch (SocketException ex)
    {
        Console.WriteLine(ex.Message);
    }

    socket.Close();
    //iocp.Dispose();
}

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
bubuko.com,布布扣

SocketAsyncEventArgs的SetBuffer函数内部会pin住buffer数据(查阅SetBufferInternal实现),它的析构函数会调用FreeOverlapped函数释放资源。而问题就是在于FreeOverlapped函数的实现和传递参数。来看一下Dispose、~SocketAsyncEventArgs的实现:

bubuko.com,布布扣
public void Dispose()
{
    this.m_DisposeCalled = true;
    if (Interlocked.CompareExchange(ref this.m_Operating, 2, 0) != 0)
    {
        return;
    }
    this.FreeOverlapped(false);
    GC.SuppressFinalize(this);
}
bubuko.com,布布扣
~SocketAsyncEventArgs()
{
    this.FreeOverlapped(true);
}

两者都会调用FreeOverlapped函数释放,但是一个传递了false、一个传递了true参数。再来看FreeOverlapped实现:

bubuko.com,布布扣
private void FreeOverlapped(bool checkForShutdown)
{
    if (!checkForShutdown || !NclUtilities.HasShutdownStarted)
    {
        if (this.m_PtrNativeOverlapped != null && !this.m_PtrNativeOverlapped.IsInvalid)
        {
            this.m_PtrNativeOverlapped.Dispose();
            this.m_PtrNativeOverlapped = null;
            this.m_Overlapped = null;
            this.m_PinState = SocketAsyncEventArgs.PinState.None;
            this.m_PinnedAcceptBuffer = null;
            this.m_PinnedSingleBuffer = null;
            this.m_PinnedSingleBufferOffset = 0;
            this.m_PinnedSingleBufferCount = 0;
        }
        if (this.m_SocketAddressGCHandle.IsAllocated)
        {
            this.m_SocketAddressGCHandle.Free();
        }
        if (this.m_WSAMessageBufferGCHandle.IsAllocated)
        {
            this.m_WSAMessageBufferGCHandle.Free();
        }
        if (this.m_WSARecvMsgWSABufferArrayGCHandle.IsAllocated)
        {
            this.m_WSARecvMsgWSABufferArrayGCHandle.Free();
        }
        if (this.m_ControlBufferGCHandle.IsAllocated)
        {
            this.m_ControlBufferGCHandle.Free();
        }
    }
}
bubuko.com,布布扣

用WinDbg查看gchandles统计:

bubuko.com,布布扣
Statistics:
              MT    Count    TotalSize Class Name
000007fb1bdb6ae8        1           24 System.Object
000007fb1bdb6b80        1           48 System.SharedStatics
000007fb1bdb7f58        1           64 System.Security.PermissionSet
000007fb1bdb6a10        1          160 System.ExecutionEngineException
000007fb1bdb6998        1          160 System.StackOverflowException
000007fb1bdb6920        1          160 System.OutOfMemoryException
000007fb1bdb6738        1          160 System.Exception
000007fb1bdb7b90        2          192 System.Threading.Thread
000007fb1bdb6c40        1          216 System.AppDomain
000007fb1bdb6a88        2          320 System.Threading.ThreadAbortException
000007fb1ae19770        6          336 System.Net.Logging+NclTraceSource
000007fb1bdbf958        3          480 System.RuntimeType+RuntimeTypeCache
000007fb1ae19900        6          480 System.Diagnostics.SourceSwitch
000007fb1bd64458        6        34520 System.Object[]
000007fb1b6f5e40     1000       112000 System.Threading.OverlappedData
Total 1033 objects

Handles:
    Strong Handles:       12
    Pinned Handles:       5
    Async Pinned Handles: 1000
    Weak Long Handles:    3
    Weak Short Handles:   13
bubuko.com,布布扣

确实存在1000个Async Pinned Handles,也就是说无法通过SocketAsyncEventArgs的析构函数释放SafeNativeOverlapped相关的资源。将示例代码的"iocp.Dispose();"注释去除,并重新执行再次查看gchandles:

bubuko.com,布布扣
Statistics:
              MT    Count    TotalSize Class Name
000007fb1bdb6ae8        1           24 System.Object
000007fb1bdb6b80        1           48 System.SharedStatics
000007fb1bdb7f58        1           64 System.Security.PermissionSet
000007fb1bdb6a10        1          160 System.ExecutionEngineException
000007fb1bdb6998        1          160 System.StackOverflowException
000007fb1bdb6920        1          160 System.OutOfMemoryException
000007fb1bdb6738        1          160 System.Exception
000007fb1bdb7b90        2          192 System.Threading.Thread
000007fb1bdb6c40        1          216 System.AppDomain
000007fb1bdb6a88        2          320 System.Threading.ThreadAbortException
000007fb1ae19770        6          336 System.Net.Logging+NclTraceSource
000007fb1bdbf958        3          480 System.RuntimeType+RuntimeTypeCache
000007fb1ae19900        6          480 System.Diagnostics.SourceSwitch
000007fb1bd64458        6        34520 System.Object[]
Total 33 objects

Handles:
    Strong Handles:       12
    Pinned Handles:       5
    Weak Long Handles:    3
    Weak Short Handles:   13
bubuko.com,布布扣

1000个Async Pinned Handles已不存在,但SocketAsyncEventArgs的析构函数从实现来看应该也可以完成释放,为什么失败了?

用!bpmd命令添加NclUtilities.HasShutdownStarted、 m_PtrNativeOverlapped.Dispose()的断点。

!bpmd System.dll System.Net.NclUtilities.get_HasShutdownStarted
!bpmd mscorlib.dll System.Runtime.InteropServices.SafeHandle.Dispose

 

 

 

 

 

SocketAsyncEventArgs的释放问题,布布扣,bubuko.com

SocketAsyncEventArgs的释放问题

标签:style   class   blog   code   java   http   

原文地址:http://www.cnblogs.com/junchu25/p/3772985.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!