欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

一次由QQ浏览器性能分析引起的性能问题

来源:本站整理 作者:佚名 时间:2018-09-13 TAG: 我要投稿

一、背景
最近有个项目用到了sysinternals出品的监控工具:sysmon.exe。但是有反馈,sysmon.exe进程(下文为方便描述简称为sysmon)在某一特定条件下,持续占用cpu,一般为会跑满cpu的一个逻辑核。例如,如果cpu为双核4线程,则sysmon的占用在25%。且sysmon占用的内存持续升高。
本文中的图是在调试环境中随本文的编写而截的,所以各位看到图中的sysmon进程PID不一致。

图 1. sysmon的高cpu、内存占用
二、问题定位与分析
问题初步定位
使用ProcessExplorer观察sysmon进程各个线程的cpu使用情况,发现各个线程的cpu占用率并不高。但是发现有大量的新线程被创建,同时又有大量的旧线程被销毁。可见,cpu时间片被主要用于线程的创建、销毁操作了。

图 2. 红色为线程销毁、绿色为线程创建
同时观察sysmon的句柄使用情况,发现句柄数量异常的高,竟然在非常短的时间内达到了万的量级。

图 3. 句柄数量异常
所以接下来的分析重点将围绕线程的大量创建和销毁以及句柄的异常创建展开。
调试器中定位问题
I. 定位线程大量创建销毁的问题
由图2可知,创建的线程都是以sysmon.exe+0x494a8这个地址开始的。顺着这个线索摸过去,发现sysmon+0x495aa这个堆栈返回地址,范围落在sysmon.exe+0x494a8这个函数的范围内。顺着sysmon+0x495aa这个栈回溯线索往回找,最终确定sysmon+0x1820e为出问题的函数,下图为sysmon各个子线程的栈回溯:

图 4. 定位到出问题的函数
分析进行到这里先暂时告一段落,稍后再验证分析的是否正确。接下来,跟进第二个问题:内存占用过高。
II. 定位内存占用过高问题
由图3可知,sysmon在段时间内创建了大量的句柄,在调试器中看下这些句柄的使用情况:

图 5. 句柄全局统计
由上图可以看到,短短几分钟之内,句柄数目由图3的4.5万多个增加到现在的72942个,其中Event类型的句柄占了72878个,比例高达99%,而且这些event都需要人工重置状态。这隐含着一个信息,在程序没有人工重置这些event的状态前,event不会被释放。短时间内创建如此量级的事件且不释放,时间久了,内存占用自然就上去了。
在调试器中确认问题
I. 内存占用过高问题的确认
通过上一节的分析,我们初步定位了cpu以及内存占用过高的原因。接下来我们来确定一下,是否是因为这个原因导致的。趁着各位刚看完内存占用过高的问题,我们先从这个问题入手。
熟悉windows编程的人可以知道,创建event一般会调用CreateEvent这个函数。那么我们在此函数上下如下断点:

解释一下这个断点的意思:首先断在kernel32.dll中的CreateEventW函数调用的开始,然后打印一下堆栈调用,最后恢复程序的执行。
OK,下面是执行结果的一部分:

图 6. 在创建Event时获取栈回溯调用
上图是大概执行了5秒钟左右的样子,从右边下拉条来看输出大概有几千条,也就是5秒钟内创建了几千个Event,这和我们上面观察到的句柄暴增现象项符。往上翻一下每次的栈回溯输出,发现都是sysmon+0x181b7这个附近出发了CreateEventW的调用。同时这里先埋个包袱:注意OpenTraceW函数。
这里同样还有另外一个需要注意的地方,就是图6中的最后一个sysmon模块的函数调用返回地址:sysmon+0x181b7。结合图4中我们定位的,离导致新线程不停被创建的地址sysmon+0x1820e很近。至于这两个地址的因果关系,详见下文分析。
II. 线程大量创建销毁的问题的确认
刚才提到 sysmon+0x181b7与sysmon+0x1820e两个地址很近,下图可以让各位在直观上了解一下两个地址究竟有多近:

图 7. sysmon+181b7与sysmon+1820e
所以,根据现在掌握的证据来看,故事很有可能是这样的:
1. 大量创建线程
2. 新创建的线程中又大量创建了Event
3. 创建的线程退出了,但是由于Event需要Manual Reset,所以Event并没有被释放
天下没有免费的午餐,这么大量的Event是需要内存存放的。所以,大量创建线程导致cpu使用变高,大量创建未释放的Event导致内存使用变高。
看到这里你可能会说,上面都是你的猜测,有什么证据支持么?下面我们在调试器中验证我们上面的猜测。在正式开始之前,我想先阐述一下我的思路:上面的分析结论是,新创建的线程导致新创建了Event;所以,如果我们下两个断点,第一个断点在sysmon+0x1820e处,第二个断点在系统的CreateEventW函数上;那么,这两个断点应该是交替命中;由于两个断点一个是位于sysmon模块的线程函数地处,另外一个则为与系统的kernel32.dll模块地址,所以两个断点理论上并没有必然联系,如果现象真的是两个断点交替命中,则可以验证我们上文的猜测。

[1] [2] [3]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载