.net 中异步SOCKET发送数据时碰到的内存问题 (二)
来源:互联网 发布:猜骰子源码 编辑:程序博客网 时间:2024/05/16 19:12
接昨天的文章
基本上我们可以认为发送数据的那一部分中有问题:每一次发送,有两个NEW的动作,产生两个新的对象。现在问题的关键是:为什么这两个新的对象没办法被回收!我们先做一实验,代码如下:
namespace Test2{ class Program { static void Main(string[] args) { Console.WriteLine("Press any key to start."); Console.ReadKey(); for (int i = 0; i < 1000000; ++i) { for (int j = 0; j < 10000; ++j) { SocketAsyncEventArgs e = new SocketAsyncEventArgs(); } System.Threading.Thread.Sleep(1000); } } }}
观察了几次,每次5分钟左右,内存波动范围:
最低:8,512K
最高:13,516K
内存不是固定在某个值,而是在这个区间内不停的变动,而且幅度比较大。估计是内存增长到一定的范围(上一章说的那个阀值?)就自动进行回收了,所 以,内存马上又下降,从而使得我们看到内存在不停的波动。
现在我们每次得到10000个对象之后,就手动处理一下内存回收,看什么结果,代码改为这样:
for (int i = 0; i < 1000000; ++i) { for (int j = 0; j < 10000; ++j) { SocketAsyncEventArgs e = new SocketAsyncEventArgs(); } GC.Collect(2); System.Threading.Thread.Sleep(1000); }
最低:8992
最高:10608
内存看起来(至少在我的机器上试了几次)稳定多了,变动的幅度也相比小一些,甚至有一会一直在(9800K-9900K)两个数字之间变化
上面的两个实验可能不是很准确,我的大概的意图是了解一下回收的效果,也可以让大家大概了解一下。
现在我们继续这个实验,当然要结合我上一文章的例子。代码如下:
namespace Test2{ class Program { static void Main(string[] args) { Console.WriteLine("Press any key to start."); Console.ReadKey(); for (int i = 0; i < 1000000; ++i) { for (int j = 0; j < 10000; ++j) { SocketAsyncEventArgs e = new SocketAsyncEventArgs(); e.SetBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1 }, 0, 10); } GC.Collect(); System.Threading.Thread.Sleep(1000); } } }}
这里把上一篇文章中的两个NEW动作都包含进来了,测试了一下,几乎是在几十秒内内存增长了60多M!
OK,问题就是出在这里了。
这里有一个明显的疑点:为什么加了这个SetBuffer 之后,内存的需求量就开始暴增呢?难道是这里new出来的byte数组没有被释放?从而导致两个新创建的对象都无法成为 dead object ?
修改代码如下:
for (int i = 0; i < 1000000; ++i) { for (int j = 0; j < 10000; ++j) { SocketAsyncEventArgs e = new SocketAsyncEventArgs(); e.SetBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1 }, 0, 10); e.SetBuffer(null, 0, 0); } GC.Collect(); System.Threading.Thread.Sleep(1000); }测试了一下,非常正确,内存稳定了~~~
现在根据这个发现去修改上一文章中的例子,每次发送完数据就取消SocketAsyncEventArgs 对 byte数组的引用。代码如下:
public bool SendAsync(byte[] bytsCmd) { //下面5行为新增加、修改的行 SocketAsyncEventArgs e = new SocketAsyncEventArgs(); e.Completed += (object s, SocketAsyncEventArgs _e) => { e.SetBuffer(null, 0, 0); }; try { e.SetBuffer(bytsCmd, 0, bytsCmd.Length); } catch (Exception ex) { lock (Program.s_lst) Program.s_lst.Add(e); System.Diagnostics.Debug.WriteLine("SetBuffer exception." + ex); return false; } try { if (m_skt.SendAsync(e)) {//Returns true if the I/O operation is pending. return true; } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine("SendAsync exception." + ex); return false; } e.SetBuffer(null, 0, 0);//新增加的行 return true; }
上面的代码还是按最初的方式处理:发送一次数据生成一个SocketAsyncEventArgs对象,但是,为了能使GC能正确的回收,在命令完成后,我们增加了e.SetBuffer(null,0,0) 这一句,以表明这几个对象都不用了,已经是 dead objects 了!
修改完后的代码测试 了20分钟,内存一直稳定在30M左右!
结论:
GC不是我们想象的那样聪明!两个dead object如果互相引用,它就没办法判断是否应该回收了!所以,用.net编程时,也要小心内存的处理,时刻要为GC着想、帮它一把!:)
- .net 中异步SOCKET发送数据时碰到的内存问题 (二)
- .net 中异步SOCKET发送数据时碰到的内存问题 (二)
- .net 中异步SOCKET发送数据时碰到的内存问题
- .net 中异步SOCKET发送数据时碰到的内存问题
- C#中异步SOCKET发送数据时内存问题
- Socket通信中碰到的链接问题
- C#或者说.NET的自动内存管理 学习中碰到的问题。
- socket 发送数据需要注意的问题
- Socket连接发送数据的一点问题
- .net socket与完成端口、异步发送
- .net C# 异步Socket 发送类.
- 异步 SOCKET 编程 - 发送和接收数据
- 异步 SOCKET 编程 - 发送和接收数据
- 异步SOCKET编程-发送和接收数据
- 异步 SOCKET 编程 - 发送和接收数据
- 异步 SOCKET 编程 - 发送和接收数据
- 异步SOCKET编程-发送和接收数据
- 异步SOCKET编程-发送和接收数据
- 当有多个设备online时,命令行窗口通过adb连接指定设备方法
- java IO (三) 字节流与缓冲
- 制约程序员"钱途"的两大最关键因素
- SimpleDateFormat做成员或者静态成员多线程安全隐患
- 联合主键二:组件映射方式
- .net 中异步SOCKET发送数据时碰到的内存问题 (二)
- 编译到执行 关于内存分配
- 一个人的Scrum之准备工作
- OpenGL函数
- cmem模块/DVSDK2.0
- Qt for android
- Oracle数据库通过undo保证一致性读和不发生脏读
- Java 终止线程方法
- MCS-51的定时/计数器