SocketAsyncEventArgs的释放问题

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


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();

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


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

~SocketAsyncEventArgs()
{
this.FreeOverlapped(true);
}

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


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();
}
}
}

用WinDbg查看gchandles统计:


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

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


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

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的释放问题

时间: 2024-12-25 04:24:24

SocketAsyncEventArgs的释放问题的相关文章

C#高性能Socket服务器SocketAsyncEventArgs的实现(IOCP)

原创性申明 本文作者:小竹zz  博客地址:http://blog.csdn.net/zhujunxxxxx/article/details/43573879转载请注明出处 引言 我一直在探寻一个高性能的Socket客户端代码.以前,我使用Socket类写了一些基于传统异步编程模型的代码(BeginSend.BeginReceive,等等)也看过很多博客的知识,在linux中有poll和epoll来实现,在windows下面 微软MSDN中也提供了SocketAsyncEventArgs这个类来

【转】C#高性能大容量SOCKET并发(二):SocketAsyncEventArgs封装

http://blog.csdn.net/sqldebug_fan/article/details/17557341 1.SocketAsyncEventArgs介绍 SocketAsyncEventArgs是微软提供的高性能异步Socket实现类,主要为高性能网络服务器应用程序而设计,主要是为了避免在在异步套接字 I/O 量非常大时发生重复的对象分配和同步.使用此类执行异步套接字操作的模式包含以下步骤:1.分配一个新的 SocketAsyncEventArgs 上下文对象,或者从应用程序池中获

C#高性能大容量SOCKET并发(二):SocketAsyncEventArgs封装

1.SocketAsyncEventArgs介绍 SocketAsyncEventArgs是微软提供的高性能异步Socket实现类,主要为高性能网络服务器应用程序而设计,主要是为了避免在在异步套接字 I/O 量非常大时发生重复的对象分配和同步.使用此类执行异步套接字操作的模式包含以下步骤:1.分配一个新的 SocketAsyncEventArgs 上下文对象,或者从应用程序池中获取一个空闲的此类对象.2.将该上下文对象的属性设置为要执行的操作(例如,完成回调方法.数据缓冲区.缓冲区偏移量以及要传

函数一直无法立即退出,在等待了大约30s后才能退出(QMulitHash释放不连续的内存需要很长世间,而这样设置局部变量后又无法避免这个问题)

局部变量使用对性能的影响以及进程的堆和栈: 由于在代码中我使用了QMulitHash<QString , LHFilteVersionItem> tmp;这一局部变量来保存某一目录下的文件,由于在写测试代码期间,我利用循环模拟了50万的数据序列化后保存在文件中,在运行期间我发现读取函数耗费很长的时间,而函数里面最耗时的读取操作也只花费了很短的时间,但是函数一直无法立即退出,在等待了大约30s后才能退出,相关代码如下: [cpp] view plain copy void LHTWORKFLOW

幸运的被释放

我们,也许出生不同,也许经历不同,但是我想,成长的过程,大部分人还是有相同的心路可寻的.比如说,步入新环境的青涩和幼稚.迷失了自我的慌乱和惶惑.甚至想要放弃自己的"出溜".压力下的软弱或坚强等等. 我们常常忽略少年愁,其实,少年的愁闷一点也不比中年的愁闷肤浅,而是两种不同的愁闷.我们在心智还不成熟的时候认识世界,成长与错误同行,经常活在对过去的悔恨或者是对未来的幻想中,于是在愁苦和矛盾中成长.而中年人的愁闷,大概是对无法改变现状乏力的愁.但是,我们常常觉得自己比较愁,这简直像是在比惨,

win10怎么关闭小娜助手释放电脑内存

不知道大家有没有觉得微软小娜助手在手机上挺实用,但是在电脑上任务栏上占用地方较大,真实的使用频率却很低,不仅仅如此而且小娜还会占用较多的电脑内存.今天我们就来说说怎么关闭小娜助手释放电脑内存. 一.同时按键盘上的Win+S键,打开小娜界面,点击左侧的齿轮图标. 二.把"Cortana可以提供建议.想法.提醒.通知等"这一项关闭,再将下面的两项也关掉. 三.点击[管理Cortana在云中了解到的我的相关内容],跳转至现金网官网并登陆账号,找到"其他Cortana数据以及个性化语

数据结构与算法 3:二叉树,遍历,创建,释放,拷贝,求高度,面试,线索树

[本文谢绝转载,原文来自http://990487026.blog.51cto.com] 树 数据结构与算法 3:二叉树,遍历,创建,释放,拷贝,求高度,面试,线索树 二叉树的创建,关系建立 二叉树的创建,关系建立2 三叉链表法 双亲链表: 二叉树的遍历 遍历的分析PPT 计算二叉树中叶子节点的数目:使用全局变量计数器 计算二叉树中叶子节点的数目:不使用全局变量计数器 无论是先序遍历,中序遍历,后序遍历,求叶子的数字都不变;因为本质都是一样的,任何一个节点都会遍历3趟 求二叉树的高度 二叉树的拷

PHP如何释放内存之unset销毁变量并释放内存详解

PHP的unset()函数用来清除.销毁变量,不用的变量,我们可以用unset()将它销毁.但是某些时候,用unset()却无法达到销毁变量占用的内存!我们先看一个例子: <?php $s = str_repeat('1',255); //产生由255个1组成的字符串 $m = memory_get_usage(); //获取当前占用内存 unset($s); $mm = memory_get_usage(); //unset()后再查看当前占用内存 echo $m-$mm; ?> 最后输出u

易宝典文章——玩转Office 365中的Exchange Online服务 之二十七 怎样处理并释放误报隔离邮件

在Exchange Online中有众多的垃圾邮件过滤功能,其过滤的结果大致分为四类: >直接拒绝接收: >放入垃圾邮件文件夹: >主题中进行标记为垃圾邮件: >隔离对于直接拒绝接收这种情况大多会针对确切到发件人.发件域.发件服务器的IP地址来进行设置,所以很少会出现误拒的情况.而放入垃圾邮件文件夹和主题中进行标注,这些垃圾邮件实际已经到了用户的邮箱.即使出现误报,用户也可以看到邮件.只有最后一种隔离邮件,如果是将用户所需要的邮件进行了隔离,那么用户往往会申请要找回这封邮件.怎样才