最近,咱们的软件在运行过程当中,遇到了一个很诡异的问题。web
软件在一个测试同事的win7 32位系统上运行1个多小时后会闪退崩溃。奇怪的是,在测试该产品的主要测试人员的win10电脑上,则从未出现过这个状况。windows
下面详细介绍一下这个问题的排查过程,以及给咱们的一些启示!服务器
一、初步分析websocket
咱们在软件中安装了异常信息捕获机制,可是软件发生闪退时,并无捕获到有效dump文件(崩溃信息存放在dump文件中),生成的dump文件是空的!多是在导出异常上下文信息时发生了二次崩溃,因此没有生成有效的dump文件。socket
这个问题在他电脑上出现过好几回了。因而,让同事将windows系统上经常使用的软件调试利器windbg挂载到目标进程上,看看复现闪退时可否抓到有效的信息。结果问题复现后,抓到的异常上下文对应的代码模块基本是不可能产生异常的,因此问题排查仍是没有头绪!ide
忽然无心中想到,软件是运行一两个小时后出现的,难道是软件中有内存泄漏?把进程的虚拟内存耗完了,致使再申请内存时都失败了,产生了空指针,致使空指针访问违例,致使软件闪退。这种假设能够解释windbg捕获到的不可能发生异常的代码块的现象了!函数
因而从新启动软件,观察了任务管理器中咱们软件对应的进程的内存占用状况。看到咱们软件的进程的内存一直在增加,在运行1个多小时后居然涨到1GB多了,这下基本能够肯定,确定是内存泄漏致使的内存被耗完,从而致使软件再申请内存失败了,致使访问了空指针,致使软件闪退了!工具
下面就是使用一些内存泄漏的检测工具来来定位内存泄漏的模块了!性能
二、使用腾讯的tMemMonitor内存泄漏检测工具检测内存泄露测试
最开始尝试使用腾讯的tMemMonitor内存泄漏检测工具,检测一下内存泄漏发生在哪一个模块中。
具体的作法是,使用tMemMonitor将咱们的软件启动起来:
让软件运行一个多小时,让软件产生1GB以上的内存泄漏,而后关闭软件,若是检测到内存泄漏就会弹出生成检测报告的提示,打开报告就能够看到检测结果了。
注意,tMemMonitor内存泄漏检测工具只能检测release版本的程序,被检测程序必须由tMemMonitor启动,而且被监测程序在退出时必须是正常退出的。若是关闭软件时发生了崩溃,tMemMonitor是不会生成内存泄漏报告的。
检测报告中会显示发生内存泄漏的dll或exe的模块名,而且会将相关的函数调用堆栈打印出来,好比:
但实际跑下来,看到检测报告,并无看到有用的信息,检测到泄漏内存的都比较小,和实际泄漏的内存大小相差甚远!难道不是用户态的内存泄漏?是内核态的内存泄漏?
三、使用windbg检测内存泄漏
使用tMemMonitor工具分析不出来,因而又尝试使用windbg分析了一把。使用此方法以前,要预先安装好windbg工具。最新版本的windbg是从内置在微软官方的SDK中的,能够自行到微软的官方网站上下载安装。
此内存泄漏检测方法,会用到windbg安装路径下的gflags.exe和umdh.exe程序,以下所示:
具体的操做步骤是:
1)打开cmd窗口,切换到windbg的安装目录中,好比个人安装路径是:C:\Program Files\Windows Kits\10\Debuggers\x86。
2)先使用命令设置用户态函数栈回溯标记:gflags /i xxxxxxxxx.exe +ust,具体含义能够以“gflags /?”查看gflags相关命令行的参数说明:
3)使用umdh.exe将时刻1时的堆内存分配状况输出到日志文件中:umdh.exe -pn:xxxxxxxxx.exe -f:E:\log1.txt。其中,umdh.exe是windows debug tools 下的一款命令行工具,它的全程是User Mode Dump Heap 这个工具会分析当前进程在堆上分配的内存。可使用“umdh /?”查看umdh.exe支持的命令行参数,以及如何使用的:
而后让程序运行一个多小时后,让程序有足够多的内存泄漏,而后再用命令:umdh.exe -pn:xxxxxxxxx.exe -f:E:\log2.txt,导出时刻2时的堆内存分配使用状况。
4)使用命令:umdh.exe E:\log1.txt E:\log2.txt -f:E:\result.txt,比较两个时刻中间的时间段的堆内存的增加及使用状况,找出可能出现内存泄漏的地方:
这彷佛仍是有问题,明明泄漏了1GB多的内存,怎么检测结果中最多泄漏的那项计算出来泄漏的内存才200MB,相差的比较多的,看来windbg彷佛也不可信啊!
四、使用代码分块注释的办法,定位到发生内存泄漏的模块
问题仍是没查出来,这个就比较头疼了,软件立刻要对外发布正式商用版本了,这个问题必需要解决啊!
最后没办法,只能采用逐步注释代码的方法,看看可否定位内存泄漏发生在哪一个模块中。经屡次尝试发现,与dcs数据协做模块的库有关系。而后查看了一下dcs服务器的链接状态,服务器连不上,底层一直在不断的定时重连,难道是每次重连失败后没有释放socket套接字等资源致使的内存泄漏?
因而找到相关模块的负责同事,让他们排查,排查下来后发现,确实是服务器重连失败后没有将相关资源释放掉致使的内存泄漏(使用websocket和服务器通讯的)!
后来在我本身的两台电脑上验证了一下,软件运行在我win7 32位电脑上是有内存泄漏的,但在我另外一台win7 64位系统上则没有内存泄漏。在测试同事的win10系统上,也详细观察了,win10系统上竟然没有内存泄漏,软件运行一切正常!这个内存泄漏难道是和操做系统是强相关的?
五、进一步研究确认
知道大概的缘由以后,我又用windbg和tMemMonitor都从新检测了一下内存泄漏,看看哪一个工具更好用,定位的更准确!
咱们选择检测的时间段内,软件已经占用了1.15GB的内存,内存泄漏估计得有900MB左右了。
此时windbg分析出来的内存泄漏模块确实是对的,以下所示:
可是泄漏的内存只有200MB左右,这和实际的内存泄漏大小有很大的出入。当前windbg分析出的内存泄漏是用户态的,可能有部分泄漏发生在程序的内核态?
而腾讯的tMemMonitor和windbg比要逊色很多,tMemMonitor不只检测出的泄漏内存大小比实际泄漏大小要小不少,并且根本没有定位到发生内存泄漏的模块。因此,windbg仍是要强大很多的。
经后来验证,在另外一台的win7 64位系统中,以前之因此没有内存泄露,是由于这台机器上登陆平台的帐号是没有dcs服务的权限,就不会登陆dcs服务器,就不会触发dcs服务器的重连。而本例中的内存泄漏就是dcs重连失败后没有清理相关资源致使的。后来使用一个有dcs服务权限的帐号在这台win7 64位系统中登陆咱们的软件,一样也出现了内存泄漏。
但一样的代码、一样的软件在win10系统中却没有内存泄漏,经过打印日志能够肯定win10系统中也触发了dcs服务器的重连了,这多是win10系统的内存管理机制和win7不一样引发的吧!
六、总结
遇到问题后,要进行深刻细致的研究,要搞清楚各类状况的前因后果!在详细的研究过程当中要多思考多验证,会有新的发现和新的收获!
【编辑推荐】
【责任编辑:华轩 TEL:(010)68476606】