走进异步世界: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 ...
随机推荐
- js模版引擎handlebars.js实用教程——另一种Helper用法
返回目录 <!DOCTYPE html> <html> <head> <META http-equiv=Content-Type content=" ...
- fildder 使用方法汇总
作为网络开发人员,怎能不使用一些抓包工具呢?fildder是个不错的选择. 不过,一般情况下,我们往往使用浏览器自带的控制台的[网络]选项就可以达到查看数据的通信情况了,当然,一些浏览器不容易捕捉的事 ...
- salesforce 零基础开发入门学习(十)IDE便捷小知识
在这里介绍两个IDE的便捷开发的小知识. 一) 本地调试 由于salesforce代码只能提交以后才能调试,所以很多时候调试代码很麻烦.新版增加了一个特性:即可以在本地调试相关的代码或者查看相关代码运 ...
- 在jQuery ajax中按钮button和submit的区别分析
在使用jQuery ajax的get方法进行页面传值,不能用submit,否则无刷新获取数据展示 点击submit提交按钮,sendPwd.php通过$_POST接收传过来的值,然后echo一段数据. ...
- python开启简单webserver
python开启简单webserver linux下面使用 python -m SimpleHTTPServer 8000 windows下面使用上面的命令会报错,Python.Exe: No Mod ...
- Linux常用命令01
Linux对于我们来说,就是跑程序的运行平台,简单的来说,就是服务器,自己也没怎么系统的学习Linux的命令,随着项目的需要, 比如要查找日志,哪里出问题了,哪里报错了,因此自己也慢慢地懂一些常用的L ...
- 重构Mybatis与Spring集成的SqlSessionFactoryBean(2)
三.代码重构 1.先使用Eclipse把buildSqlSessionFactory()方法中众多的if换成小函数 protected SqlSessionFactory buildSqlSessio ...
- SSIS Component的ValidateExternalMetadata属性
ValidateExternalMetadata Property Indicates whether the component validates its column metadata agai ...
- JSP网站开发基础总结《十二》
前两篇已经简单为大家介绍了一下,有关Filter接口的知识,本篇就让我们以一个登录小功能,来具体实现一下过滤器的作用,便于大家掌握.具体为大家介绍一下如何使用Filter对访问进行过滤,及如何防止中文 ...
- Gephi可视化(一)——使用Gephi Toolkit创建Gephi应用
在Prefuse上摸打滚爬了一段时间,发现其和蔼可亲,容易上手.但是每每在打开gephi,导入数据再运行时,总还是在心里暗自赞叹gephi的绚烂之极,无与匹敌,当然,gephi也有自己的缺陷,但是ge ...