走进异步世界:EnyimMemcached异步化改造引起的内存泄漏
6月30日我们发布了异步化改造后的博客程序之后,出现了高内存、高CPU、高线程数的不理想情况。
经过一周的追查,终于水落日出——引起不理想情况的根源是我们修改过的EnyimMemcached代码存在内存泄漏问题。
而造成内存泄漏的根源是我们没有对SocketAsyncEventArgs进行Dispose,实际情况是我们当时根本没注意到SocketAsyncEventArgs实现了IDispose接口,而这个小小的疏忽竟然折腾了我们一个星期。
存在内存泄漏问题的代码是这样写的:
a) 异步从Socket中读取数据:
public async Task<byte[]> ReadBytesAsync(int count)
{
var args = new SocketAsyncEventArgs();
args.SetBuffer(new byte[count], , count);
var awaitable = new SocketAwaitable(args);
await this.socket.ReceiveAsync(awaitable);
return args.Buffer;
}
b) 异步向Socket中写入数据:
public async Task WriteSync(IList<ArraySegment<byte>> buffers)
{
var args = new SocketAsyncEventArgs();
args.BufferList = buffers;
var awaitable = new SocketAwaitable(args);
await this.socket.SendAsync(awaitable);
}
解决内存泄漏问题的方法很简单,using+Buffer.BlockCopy,代码如下:
a) 改进后的异步从Socket中读取数据:
public async Task<byte[]> ReadBytesAsync(int count)
{
using (var args = new SocketAsyncEventArgs())
{
args.SetBuffer(new byte[count], , count);
var awaitable = new SocketAwaitable(args);
await this.socket.ReceiveAsync(awaitable);
var receivedBytes = new Byte[args.BytesTransferred];
Buffer.BlockCopy(args.Buffer, , receivedBytes, , args.BytesTransferred);
return receivedBytes;
}
}
b) 改进后的异步向Socket中写入数据:
public async Task WriteSync(IList<ArraySegment<byte>> buffers)
{
using (var args = new SocketAsyncEventArgs())
{
args.BufferList = buffers;
var awaitable = new SocketAwaitable(args);
await this.socket.SendAsync(awaitable);
}
}
改进后的代码已发布至github:https://github.com/cnblogs/EnyimMemcached。
你也许会问我们是如何监测到内存泄漏情况的呢?
我们借助于两个工具:Windows任务管理器与性能监视器。
1. 通过任务管理器,我们观察到w3wp占用的内存会持续增长,当到达5G左右,在8核8G的阿里云虚拟机上CPU就开始做坐过山车,只有回收程序池(重启w3wp进程)才能恢复正常。
2. 通过性能监视器,我们监测了两个指标:
a) \.NET CLR Memory(w3wp)\# Bytes in all Heaps (针对托管内存)
b) \Process(w3wp)\Private Bytes (针对非托管内存)
观察到的情况见下图:

(绿色是Private Bytes)
Bytes in all Heaps与Private Bytes都会出现持续增长。
而对SocketAsyncEventArgs进行Dispose之后,性能监视器看到的\.NET CLR Memory\# Bytes in all Heaps变成了这样:

\Process\Private Bytes也与Bytes in all Heaps相映成辉:

一看到这样的图形,你应该和我们一样感觉到了GC在背后辛勤工作的身影。
走进异步世界:EnyimMemcached异步化改造引起的内存泄漏的更多相关文章
- 走进异步世界-犯傻也值得分享:ConfigureAwait(false)使用经验分享
在上周解决“博客程序异步化改造之后遭遇的性能问题”的过程中,我们干了一件自以为很有成就感的事——在表现层(MVC与WebForms)将所有使用await的地方都加上了ConfigureAwait(fa ...
- Dubbo 2.7新特性之异步化改造
这是why技术的第1篇原创文章 我与Dubbo的二三事 我是2016年毕业的,在我毕业之前,我在学校里面学到的框架都是SSH,即struts+spring+hibernate,是的你没有看错,在大学里 ...
- JS的异步世界
前言 JS的异步由来已久,各种异步概念也早早堆在开发者面前.可现实代码中,仍然充斥了各种因异步顺序处理不当的bug,或因不好好思考,或因不了解真相.今天,就特来再次好好探索一番JS的异步世界. 01 ...
- 小丁带你走进git世界一-git简单配置
小丁带你走进git世界一-git简单配置 1.github的简单配置 配置提交代码的信息,例如是谁提交的代码之类的. git config –global user.name BattleHeaer ...
- [.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序
[.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序 本节导读: 本节主要说明使用异步进行程序设计的优缺点及如何通过异步编程. 使用 ...
- arm驱动linux异步通知与异步IO【转】
转自:http://blog.csdn.net/chinazhangzhong123/article/details/51638793 <[ arm驱动] linux异步通知与 异步IO> ...
- C#“同步调用”、“异步调用”、“异步回调”
本文将主要通过“同步调用”.“异步调用”.“异步回调”三个示例来讲解在用委托执行同一个“加法类”的时候的的区别和利弊. 首先,通过代码定义一个委托和下面三个示例将要调用的方法: ); //模拟该方法运 ...
- Linux设备驱动中的异步通知与异步I/O
异步通知概念: 异步通知的意识是,一旦设备就绪,则主动通知应用程序,这样应用程序根本就不需要查询设备状态,这一点非常类似于硬件上的“中断”概念,比较准确的称谓是“信号驱动的异步IO”,信号是在软件层次 ...
- Oracle 12C 新特性之表分区带 异步全局索引异步维护(一次add、truncate、drop、spilt、merge多个分区)
实验准备:-- 创建实验表CREATE TABLE p_andy(ID number(10), NAME varchar2(40))PARTITION BY RANGE (id)(PARTITION ...
随机推荐
- HTML5打造的炫酷本地音乐播放器-喵喵Player
将之前捣腾的音乐频谱效果加上一个播放列表就成了现在的喵喵播放器(Meow meow Player,额知道这名字很二很装萌~),全HTML5打造的网页程序,可本地运行也可以挂服务器上用. 在线Demo及 ...
- IOS 多线程05-OperationQueue 、GCD详解
注:本人是翻译过来,并且加上本人的一点见解. 1. 开始 目前在 iOS中有两套先进的同步 API 可供我们使用:操作队列OperationQueue和 GCD .其中 GCD 是基于 C 的底层 ...
- jQuery_04之第三方、自定义
1.第三方插件: ①日期:layDate:不依赖于jquery 使用:html:<input class="laydate-icon"> css:引入laydat ...
- Unity3D Editor模式下批量修改prefab
最经遇到一个需要批量修改已经做好的prefab的问题,查了一些资料最终实现了但是还是不够完美,通过学习也发现unity的编辑器功能还是非常强大的.废话不多说直接上代码: [ExecuteInEditM ...
- js算法之最常用的排序
引入 大学学习计算机语言的那几年,从c语言,到c++,再到数据结构JAVA..让我印象最深刻的还是最开始老师讲冒泡算法的时候,直到现在大四快毕业了我才渐渐通窍了.刚学前端的时候以为前端就是做出好看很炫 ...
- 关于Thread.currentThread()和this的差异
重新来看多线程时,被这结果搞懵逼了.不多说,直接上代码: public class MyThread02 extends Thread { public MyThread02() { System.o ...
- 使用模板技术处理ASP.NET中GridView额外序号列的问题
问题描述: 现在要在一张GridView表中添加一列来显示行号,要求是显示下一页的时候能够递增而不是从新编号.数据库中的没有相关序号列 如何在软件端实现呢? 通过测试,添加以下代码即可解决需求. &l ...
- poj3422 Kaka's Matrix Travels(最小费用最大流问题)
/* poj3422 Kaka's Matrix Travels 不知道 k次 dp做为什么不对??? 看了大牛的代码,才知道还可以这样做! 开始没有理解将a 和 a‘ 之间建立怎样的两条边,导致程序 ...
- python类定义与c#的一些区别
c#中可以定义一个空类,但是python中定义空类需要加pass class EmptyClass(object): pass python的lei是多继承 python子类继承了基类,如果子类也 ...
- 如何配置Hyper-V的虚拟机通过主机网络上网 (NAT)
前言 最近开始在Windows 8 上面直接使用Hyper-V的技术来建立虚拟环境进行开发和测试,这样免去了再安装额外软件的需要.在实际使用的时候,尤其是配置网络共享的时候,遇到些问题,与其他一些虚拟 ...