windbg分析一次大查询导致的内存暴涨
项目上反馈了一个问题,就是在生产环境上,用户正常使用的过程中,出现了服务器内存突然暴涨,客户有点慌,想找下原因。
讲道理,内存如果是缓慢上涨一直不释放的话,应该是存在内存泄漏的,这种排查起来比较困难,还得找开发一块看;但像这种突然暴涨的,肯定是把某些大对象放到内存里了,而最有可能的,就是大查询了,比如把几百万数据查出来这种,但这种一般等用户用完这个功能内存就会降下来。
环境:IIS+.net framework。发现是w3wp进程一直在涨内存,也就是iis,确实是程序的锅。
分析内存问题的话,一般是在持续上涨的过程中,多抓几个dump,看看哪些对象没释放,便于分析,这次用户只抓了一个dump,要不然太大了,传到我本机也费事。
那就开始分析吧。
首先找了个本地测试环境,用windbg加载dump,加载分析文件,幸运的是,.loadby sos clr一次成功了,后续分析都没啥问题,不用再从客户那边拷贝sos,clr这些文件;
这是用户正常业务场景的dump,也不知道当时多少人用,都在干什么,既然是内存问题,先看下内存中的对象情况吧:
!dumpheap -stat

果不其然,出现了DataRow的影子,估计是有个大查询没跑了。但是是什么场景?哪个sql?查出来多少数据?这个得继续分析了。
需要注意的是,抓这个dump的时候,内存3g多,dump大小也3g多,但是DataRow这个对象总共才46M,为什么要看这个对象,不看其他的呢?
要知道,分析的话,从占用大的对象开始分析是没问题,但是得看这个对象是不是比较特殊,像是上边占用最高的是string,1g多,但是string太普遍了,数量多也正常,而且不好分析,但DataRow这个肯定是访问数据库了,这种对象好分析。
再就是,为什么才46M,这个涉及到托管内存和非托管内存了。c#是基于.net的高级编程语言,所谓的托管,其实是指内存的托管,就是当写代码需要new一个新对象的时候,是不需要考虑内存申请与销毁的,.net自动给你做了,所以,当你抓了一个6g的dump,可能里边的托管内存才2g,剩余4g非托管内存里的东西从windbg是看不到的,非托管内存的增长,肯定是由托管代码引起的,所以这个地方虽然DataRow只有46M,但是由这个引起的内存增长是不可知的。
那接下来就看看工作线程数和堆栈吧,对当时的业务场景、使用人数大概有个了解:
!threads -special

工作线程数不是很多,说明同时使用的人不多,应该不会有太大的压力,所以可能是某一个或者某几个线程引起的,那就看下堆栈情况,大致了解下使用场景,猜一下是哪个场景引起的:
~* e!clrstack 打印下所有线程的堆栈
本来工作线程就不多,有业务含义并且和数据库相关的堆栈就更少了,看了下,大致有三个场景:
一个貌似是在判断权限:

一个貌似是个财务的往来单位查询:

还有一个貌似是财务的凭证查询:

具体是哪个引起的就得继续分析了,可以分别进入这三个线程,看下线程里的对象情况。
比如,切换到往来单位查询的那个线程里(线程id是107),然后通过!dso命令查看下当前线程的对象:
~107 s
!dso

直接就看到一个sql了,看下这个线程里的DataRow吧,看看它是不是它的锅:
!do 0000006231d5af28

查看下所在的DataTable信息:
!do 0000006027566878

从elementColumnCount能看出来,当前是查询出来了89列;看的时候,要看下Type列,看看当前的对象类型,哪些是你需要和关注的。
然后再看recordManager,看下查询出来的记录信息,也就是行信息:
!do 0000006027566b08

recordCapacity,行容量,524288,即查询出来的行为52w。
至此,应该明了了,就是往来单位查询场景,上边的那个sql(当然也可以通过!dso中sqlCommand对象查看Text,确认具体的sql),查询出来了52w行,89列,导致的内存暴涨。
后来通过跟开发与用户确认,确实是这个查询界面上,没有选具体的单位,然后关联了一张600w数据的表,最终查出了52w行数据导致的。实际用户的业务场景是需要具体单位的,这种场景没做跨单位查询的权限控制,用户又恰巧没选单位,所以出现了这个问题。后来开发把单位加了必选,该问题解决。
windbg分析一次大查询导致的内存暴涨的更多相关文章
- apache不断占内存过大,导致虚拟机内存不足,处理方法。
我用512M的vps,访问量不大,但内存占用很大,甚至宕机. 我用top,然后shitf+m发现,httpd占用内存极大.经过网上找资料设置后,用过一段时间终于没再出现内存问题了. 首先查找配置文件的 ...
- 利用windbg分析崩溃,句柄泄漏,死锁,CPU高,内存泄漏
Windbg的一些简单使用命令 一.崩溃 1. 输入.ecxr;kbn得到崩溃的堆栈 其中源代码如下 2. 查看堆栈和源代码,发现第0帧导致崩溃,代码也是本地代码 输入.frame 0,切到第0 ...
- 利用Windbg分析Magicodes.IE一次错误编写导致内存剧增
由于这近一年时间一直忙于写书和工作,一直没有水文,但是近期有几位朋友使用我们的Magicodes.IE反馈在导出过程中内存暴涨...好吧,不管怎样,不能苦了我们朋友,接下来我们通过windbg来看一下 ...
- 揪出“凶手”——实战WinDbg分析电脑蓝屏原因
http://www.appinn.com/blue-screen-search-code/ 蓝屏代码查询器 – 找出蓝屏的元凶 11 文章标签: windows / 系统 / 蓝屏. 蓝屏代码查询器 ...
- Windbg分析高内存占用问题
1. 问题简介 最近产品发布大版本补丁更新,一商超客户升级后,反馈系统经常奔溃,导致超市的收银系统无法正常收银,现场排队付款的顾客更是抱怨声声.为了缓解现场的情况, 客户都是手动回收IIS应用程序池才 ...
- 《MySQL》一次MySQL慢查询导致的故障
本文转载自 http://www.jb51.net/article/70955.htm 我们知道分析MySQL语句查询性能的方法除了使用EXPLAIN 输出执行计划,还可以让MySQL记录下查询超过指 ...
- Android大图片导致内存问题小结
在网上看了部分Android中OOM的问题,现在根据理解,做一下笔记. Android OOM 产生的几种原因 1. 程序中使用了太多自己创建的Bitmap. 这种情况通常是最好解决的. 因为你明白你 ...
- 关于ODP.NET连接数监控及相应的windbg分析提示
1.关于ODP.NET的Windows计数器问题 使用微软的缺省驱动时,可以通过windows性能监视器很方便的监控数据库连接数,选择.NET Data Provider for Oracle/Sql ...
- Windbg分析蓝屏Dump文件
一.WinDbg是什么?它能做什么? WinDbg是在windows平台下,强大的用户态和内核态调试工具.它能够通过dmp文件轻松的定位到问题根源,可用于分析蓝屏.程序崩溃(IE崩溃)原因,是我们日常 ...
随机推荐
- 【scrapy运行姿势】scrapy.cmdline.execute
scrapy.cmdline.execute scrapy的cmdline命令 1.启动爬虫的命令为:scrapy crawl (爬虫名) 2.还可以通过以下方式来启动爬虫 方法一:创建一个.py文件 ...
- JS轮播图带序号小点和左右按钮
轮播图作为前端比较简易的动画,使用非常频繁,这里记录以便使用 此轮播图为最简易自动播放,非无缝,但有按钮,有序号跳转小点 想看全套轮播图可以查看我的分类轮播图全套 html布局 <div sty ...
- 简单的认识Linux
一:电脑硬件种类说明 1. 服务器的分类: <1>外观分类:机架式,塔式,刀片式/服务器. <2>尺寸分类:1u,2u,3u <3>性能分类:pc服务器,小型机服 ...
- LeetCode DFS搜索与回溯专题
DFS + 回溯专题 17. 电话号码的字母组合 迭代也可以实现搜索 循环改写dfs搜索的写法: 例如 C++写法 class Solution { public: vector<string& ...
- Docker安装常见的应用与将本地镜像推送到阿里云
一.Docker安装常用的应用 1,docker安装mysql #拉取镜像mysql5.7 docker pull mysql:5.7 #启动容器(绑定对应的配置文件和日志,默认密码为123456) ...
- Magicodes.SwaggerUI 已支持.NET Core 3.1
Magicodes.SwaggerUI 通过配置文件简单配置即可快速完成SwaggerUI的配置,包括: SwaggerUI的文档信息 API分组 API隐藏 API JSON生成(枚举.API架构I ...
- vue中 vue-awesome-swiper的使用
在页面开发中,经常会碰到需要轮播,滑动等需求,特别是多元素滑动,此时,要么自己写,要么网上找轮子,不过自己写,其实还是有点难度的,一般就是网上找写好的库,本文就是针对vue-awesome-swipe ...
- 4.String字符串类型操作
String类型操作 1.set key value 设置key对应的值为string类型的value 2.mset key1 value1 … keyN valueN 一次设置多个key的值 3. ...
- 创建多线程的方式&Thread类的常用方法
创建多线程的第一种方式:继承java.lang.Thread类 注意:1.一个线程只能执行一次start() 2.不能通过Thread实现类对象的 run()去启动一个线程 3.增加加一个线程,需要新 ...
- Python装饰器的一点解读
版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/12977127.html 作者:窗户 ...