【腾讯TMQ】win32应用程序性能测试-内存篇
2017-01-04 15:51
281 查看
本文主要讲述windows平台下应用程序性能测试的内存相关的知识,通过本文了解内存基本原理和分析内存占用问题。
虚拟内存:每个32位的进程操作系统为其分配最大4G的线性虚拟地址空间,地址是从0X00000000~0XFFFFFFFF 其中低的2G留给进程,高的2G留给系统。
例如我的电脑配置是 :如下,安装的内存是16G。查看资源监视器里显示,所以平时所说的内存占用是指物理内存。
2)内存在资源管理器概念
例如这里进程: 物理内存(工作集)=可共享+专用工作集:是私人工作集中的内存数量与进程正在使用且可以由其他进程共享的内存数量的总和。
专用工作集:- 是工作集的一个子集,专用工作集专门描述了某个进程正在使用的且无法与其他进程共享的内存数量。
提交大小:是为某进程使用而保留的虚拟内存的数量。
3)虚拟内存查看
虚拟内存,用VMMAP工具查看。如下图
具体含义可以去网上搜索。其中虚拟内存有三种状态:
1)自由(free)是指内存还未使用。
2)当申请内存使用VirtualAlloc传入MEM_RESERVE执行预留(reserved)操作。
3)当真正访问内存的数据才执行提交(committed),传入MEM_COMMINT参数。
Freelist :可用来分配,但是含有脏数据
modified:以前属于某个进程,但是需要写入到后备存储,为备后面恢复
standby :跟进程关联,但是不计算在工作集里
zero:置0后用来分配
可缓存内存是指在smodified和standby上的,可用的内存是指在zero \free\standby lists,如果这个值小于800M的话。windows就会消减工作集,会导致整体性能变差。
2)操作系统有两个线程会执行一些操作,一个是zero page thread,当要将free page移动到zeroed page时 进行置0 free page
3)第二个是 modified page writer,将modified page list移动到 standby page list时,进行第一次写出任何数据
页错误
1)什么是页错误
访问数据时,进行虚拟地址映射到物理地址过程中,硬件检查页表时,发现所访问的页面不在内存,就产生异常–缺页异常,这个缺页异常就叫做页错误。操作系统会执行缺页异常处理程序:获得磁盘的地址、启动磁盘、将该页调入内存。如下图,是<<微软核心编程>>里例子,当访问的数据不在内存中就会发生一次fault,其中当访问page不在modified和standy里,则会发生HardPageFault。HardPageFault需要去系统的pagefile.sys里查找,这个查找过程会产生大量的IO操作,影响性能。
2)页错误的类型
Transition:是指访问的page是指在 modify或者stadby page list上DemandZero:进程请求内存是,调用是zero page listHardPageFault:访问的page不在工作集里,需要去磁盘pagefile去查找copy on write:写入copy-on-write page。例如你要hook一个kernel上的函数,就是操作kernel上的page,需要先拷贝一份,这样不会影响其它进程使用kernel上的函数,这个操作就会发生一次copy on write错误
内存的分配API
1)利用 HeapAlloc 方法或 C/C++ 运行时中的 malloc 或 new 来进行堆内存分配。
2)利用 VirtualAlloc 方法从系统中直接分配内存。VirtualAlloc是Windows提供的API,通常用来分配大块的内存
3)由内核通过 CreateFile, CreateEvent, or CreateThread 等 Kernel32 APIs ,来代表应用程序进行处理
4)利用 User32 和 Gdi32 APIs 来处理 GDI 和 USER 。(默认情况下,每一个线程都有 10,000 处理( 10,000 handles )配额)
1)原理
函数用来设置应用程序最小和最大的运行空间,只会保留需要的内存,例如我们的部分exe里是有刷内存,这里设置的最小8M,最大14M
2)缺点
刷内存只是将可能暂时不需要工作集swap出去,如果业务又再需要,需从虚拟内存的pagefile里调用过来,这个过程反而降低系统性能,所以不推荐使用
分析过程1)抓取对应exe启动过程中VirtualAlloc。
2)查看启动过程中过程中VirtualAlloc分配的类型是AIFO【AIFO是指在此阶段分配但未释放,这种就是可疑的分配点】。发现其中有一段每次分配495K
3)查看对应的分配堆栈如下,发现是调用
CreateToolhelp32Snapshot方法,引起这次分配。查看系统API。CreateToolhelp32Snapshot可以通过获取进程信息为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程建立一个快照。
4)查看源码,发现这里是每隔3S,去查询系统所有进程的一个快照,所以每次大小都有接近500K。而且场景的触发频率非常高,每隔1S检测一次,后面跟开发核实,这里的逻辑不应如此设计
5)通过这个问题,我们可以去系统检索一个分配内存大的函数,例如CreateToolhelp32Snapshot,是不是所有触发逻辑合理,轮询调用是非常不合理,应该要规避,而且这个代码是常驻的。这个留在后面形成相应的规则
方法一、在内存增长时,trace。缺点:无法准确捕获这个时刻
方法二、看图,应该在1个半小时能出现,一直trace这个过程的VirtualAlloc和heapAlloc。因xperf开启heapalloc 消耗太大,只能针对指定进程进行trace
2)复现过程:
安装同样的版本,发现本地也会出现VM从32M最后涨到50M的情况。
设计trace的日志
Xperf -on PROC_THREAD+LOADER+CSWITCH+DISPATCHER+VIRT_ALLOC -stackwalkCSwitch+ReadyThread
xperf -start HeapSession -heap -Pids 18908 -BufferSize 1024 -MinBuffers 128 -MaxBuffers 128 -stackwalkHeapAlloc+HeapRealloc
如下图,查看到这个过程有几个分配大的点。其中有一个1M到4M,增长3M的情况和对应的堆栈。
其中0xfd10000这个对象分配3.176M,这个堆栈全部都是系统的API
对应CPU调度图来查看是什么原因导致这个分配,这里表现是一个TPKTT.dll
查看当时的内存dump,查看0xfd10000对象,调用的堆栈是文件监控里
结合上面,怀疑是文件监控导致的,但是跟开发确认文件监控很久未变更,而且文件监控是底层逻辑,所有业务会触及。另一方面,查看TPKTT.dll相关的信息,他们的里面的逻辑没有泄露点
是不是挂机的现象和我这不一样,同样在挂机的机器上抓trace日志,最后问题点是一样的
再次分析内存分配的堆栈,向前查看,发现调用文件监控逻辑前有一个Loadlibrary的操作,而且TPKTT.dll的大小正好也是3M多
开发再次排查他们的逻辑,原来在静默1个小时后,会触发引擎的TPK的逻辑,这里,概会增加10到13M的样子,所以RTP VM 增加属于业务的需要,引擎库加载需要内存。这个逻辑触发在70分钟到90分钟之间。因为我们的挂机以前只挂1个小时,这次是因为验证其它问题,所以挂机时间长出现这个问题。经过2天的定位,终于确认这次增长。
附我们内存优化的一些方向:
参考文章:
https://blogs.msdn.microsoft.com/tims/2010/10/29/pdc10-mysteries-of-windows-memory-management-revealed-part-two/
【TMQ新书专栏】https://weidian.com/?userid=984448577
原文链接:http://tmq.qq.com/2017/01/application_test_memory/
关注我们的微信公众号查看完整内容哦~~~~
想知道更多测试相关干货
请关注我们的微信公众号:腾讯移动品质中心TMQ
二维码:
版权声明:腾讯TMQ拥有内容的全部版权,任何人或单位对本贴内容进行复制、转载时请申明原创腾讯tmq,否则将追究法律责任。
一、内存是什么?
1.内存分为物理内存和虚拟内存
物理内存指通过物理内存条而获得的内存空间,虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间)。2.两者都有系统约定的最大值
进程占用的内存一般是指物理内存,其中操作系统为每个进程的工作集定义了一个最小和最大工作集。每个进程的 工作集有最小工作集(20-50M)最大是45-345M虚拟内存:每个32位的进程操作系统为其分配最大4G的线性虚拟地址空间,地址是从0X00000000~0XFFFFFFFF 其中低的2G留给进程,高的2G留给系统。
3.查看物理内存和虚拟内存
1)电脑配置例如我的电脑配置是 :如下,安装的内存是16G。查看资源监视器里显示,所以平时所说的内存占用是指物理内存。
2)内存在资源管理器概念
例如这里进程: 物理内存(工作集)=可共享+专用工作集:是私人工作集中的内存数量与进程正在使用且可以由其他进程共享的内存数量的总和。
专用工作集:- 是工作集的一个子集,专用工作集专门描述了某个进程正在使用的且无法与其他进程共享的内存数量。
提交大小:是为某进程使用而保留的虚拟内存的数量。
3)虚拟内存查看
虚拟内存,用VMMAP工具查看。如下图
具体含义可以去网上搜索。其中虚拟内存有三种状态:
1)自由(free)是指内存还未使用。
2)当申请内存使用VirtualAlloc传入MEM_RESERVE执行预留(reserved)操作。
3)当真正访问内存的数据才执行提交(committed),传入MEM_COMMINT参数。
二、系统如何管理内存
1.系统使用PFN数据库
系统使用PFN(Page Frame Number)数据库来存储物理内存。分几类page list来存储,如下面的图Freelist :可用来分配,但是含有脏数据
modified:以前属于某个进程,但是需要写入到后备存储,为备后面恢复
standby :跟进程关联,但是不计算在工作集里
zero:置0后用来分配
可缓存内存是指在smodified和standby上的,可用的内存是指在zero \free\standby lists,如果这个值小于800M的话。windows就会消减工作集,会导致整体性能变差。
2/操作过程
1)windows启动时,所有的内存全部是在 free page list.当进程请求内存时,(我理解为发生一次错误,从zero page file)。进程退出,则会将内存还到 free page list。2)操作系统有两个线程会执行一些操作,一个是zero page thread,当要将free page移动到zeroed page时 进行置0 free page
3)第二个是 modified page writer,将modified page list移动到 standby page list时,进行第一次写出任何数据
页错误
1)什么是页错误
访问数据时,进行虚拟地址映射到物理地址过程中,硬件检查页表时,发现所访问的页面不在内存,就产生异常–缺页异常,这个缺页异常就叫做页错误。操作系统会执行缺页异常处理程序:获得磁盘的地址、启动磁盘、将该页调入内存。如下图,是<<微软核心编程>>里例子,当访问的数据不在内存中就会发生一次fault,其中当访问page不在modified和standy里,则会发生HardPageFault。HardPageFault需要去系统的pagefile.sys里查找,这个查找过程会产生大量的IO操作,影响性能。
2)页错误的类型
Transition:是指访问的page是指在 modify或者stadby page list上DemandZero:进程请求内存是,调用是zero page listHardPageFault:访问的page不在工作集里,需要去磁盘pagefile去查找copy on write:写入copy-on-write page。例如你要hook一个kernel上的函数,就是操作kernel上的page,需要先拷贝一份,这样不会影响其它进程使用kernel上的函数,这个操作就会发生一次copy on write错误
内存的分配API
1)利用 HeapAlloc 方法或 C/C++ 运行时中的 malloc 或 new 来进行堆内存分配。
2)利用 VirtualAlloc 方法从系统中直接分配内存。VirtualAlloc是Windows提供的API,通常用来分配大块的内存
3)由内核通过 CreateFile, CreateEvent, or CreateThread 等 Kernel32 APIs ,来代表应用程序进行处理
4)利用 User32 和 Gdi32 APIs 来处理 GDI 和 USER 。(默认情况下,每一个线程都有 10,000 处理( 10,000 handles )配额)
三、如何优化内存占用高的问题
1.刷内存
刷内存SetProcessWorkingSetSize1)原理
函数用来设置应用程序最小和最大的运行空间,只会保留需要的内存,例如我们的部分exe里是有刷内存,这里设置的最小8M,最大14M
2)缺点
刷内存只是将可能暂时不需要工作集swap出去,如果业务又再需要,需从虚拟内存的pagefile里调用过来,这个过程反而降低系统性能,所以不推荐使用
2.减少页错误
这里推荐的操作是预处理,减少随机IO等。3.查找占用不合理和分配不合理的地方
1)例子:某个dll 申请内存不合理分析过程1)抓取对应exe启动过程中VirtualAlloc。
2)查看启动过程中过程中VirtualAlloc分配的类型是AIFO【AIFO是指在此阶段分配但未释放,这种就是可疑的分配点】。发现其中有一段每次分配495K
3)查看对应的分配堆栈如下,发现是调用
CreateToolhelp32Snapshot方法,引起这次分配。查看系统API。CreateToolhelp32Snapshot可以通过获取进程信息为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程建立一个快照。
4)查看源码,发现这里是每隔3S,去查询系统所有进程的一个快照,所以每次大小都有接近500K。而且场景的触发频率非常高,每隔1S检测一次,后面跟开发核实,这里的逻辑不应如此设计
5)通过这个问题,我们可以去系统检索一个分配内存大的函数,例如CreateToolhelp32Snapshot,是不是所有触发逻辑合理,轮询调用是非常不合理,应该要规避,而且这个代码是常驻的。这个留在后面形成相应的规则
2.例子:是内存泄露还是?
例子:某个版本的资源挂机突然VM增加,是内存泄露还是?1)现象:如下图一个内部版本,在某个长时间挂机,突然出现在1个小时和4个小时后,内存增长10M的样子。时间跨度长,如何获取增长时的内存分配堆栈?方法一、在内存增长时,trace。缺点:无法准确捕获这个时刻
方法二、看图,应该在1个半小时能出现,一直trace这个过程的VirtualAlloc和heapAlloc。因xperf开启heapalloc 消耗太大,只能针对指定进程进行trace
2)复现过程:
安装同样的版本,发现本地也会出现VM从32M最后涨到50M的情况。
设计trace的日志
Xperf -on PROC_THREAD+LOADER+CSWITCH+DISPATCHER+VIRT_ALLOC -stackwalkCSwitch+ReadyThread
xperf -start HeapSession -heap -Pids 18908 -BufferSize 1024 -MinBuffers 128 -MaxBuffers 128 -stackwalkHeapAlloc+HeapRealloc
注:第二条是开启heapsession来trace 指定进程的heapalloc。整个过程etl太大,全部需要输出到文件模式
分析trace过程的分配。如下图,查看到这个过程有几个分配大的点。其中有一个1M到4M,增长3M的情况和对应的堆栈。
其中0xfd10000这个对象分配3.176M,这个堆栈全部都是系统的API
对应CPU调度图来查看是什么原因导致这个分配,这里表现是一个TPKTT.dll
查看当时的内存dump,查看0xfd10000对象,调用的堆栈是文件监控里
结合上面,怀疑是文件监控导致的,但是跟开发确认文件监控很久未变更,而且文件监控是底层逻辑,所有业务会触及。另一方面,查看TPKTT.dll相关的信息,他们的里面的逻辑没有泄露点
是不是挂机的现象和我这不一样,同样在挂机的机器上抓trace日志,最后问题点是一样的
再次分析内存分配的堆栈,向前查看,发现调用文件监控逻辑前有一个Loadlibrary的操作,而且TPKTT.dll的大小正好也是3M多
开发再次排查他们的逻辑,原来在静默1个小时后,会触发引擎的TPK的逻辑,这里,概会增加10到13M的样子,所以RTP VM 增加属于业务的需要,引擎库加载需要内存。这个逻辑触发在70分钟到90分钟之间。因为我们的挂机以前只挂1个小时,这次是因为验证其它问题,所以挂机时间长出现这个问题。经过2天的定位,终于确认这次增长。
四、结尾
性能里调优内存涉及的点比较多,上面几个例子只是部分。建议平时先建设基础基准数据,有业务增加及时定位。附我们内存优化的一些方向:
参考文章:
https://blogs.msdn.microsoft.com/tims/2010/10/29/pdc10-mysteries-of-windows-memory-management-revealed-part-two/
【TMQ新书专栏】https://weidian.com/?userid=984448577
原文链接:http://tmq.qq.com/2017/01/application_test_memory/
关注我们的微信公众号查看完整内容哦~~~~
想知道更多测试相关干货
请关注我们的微信公众号:腾讯移动品质中心TMQ
二维码:
版权声明:腾讯TMQ拥有内容的全部版权,任何人或单位对本贴内容进行复制、转载时请申明原创腾讯tmq,否则将追究法律责任。
相关文章推荐
- 【腾讯TMQ】【Android场景化性能测试】内存性能及内存泄漏篇
- 【腾讯TMQ】Google是如何做Chrome浏览器的性能测试的?
- 【腾讯TMQ】GT3.1简化您的App性能测试(1)——全新的性能监测体系
- 【腾讯TMQ】【Android场景化性能测试专栏】CPU耗电性能篇
- 【腾讯TMQ】移动H5性能测试平台解决方案
- 【腾讯TMQ】【Android场景化性能测试专栏】方向与框架篇
- 【腾讯TMQ】【Android场景化性能测试】UI流畅度篇
- 【腾讯TMQ】【Android场景化性能测试】启动速度篇
- 将 Win32 C/C++ 应用程序迁移到 POWER 上的 Linux,第 1 部分: 进程、线程和共享内存服务 (转)
- 使用开源的Profiler来测试你的Java应用程序的性能
- 使用开源的Profiler来测试你的Java应用程序的性能
- 性能测试总结之内存泄露和内存溢出
- 使用开源的Profiler来测试你的Java应用程序的性能
- 将Win32 C/C++应用程序迁移到Linux-进程、线程和共享内存
- 性能测试之内存泄漏
- 启用 ASP.NET 应用程序跟踪(性能测试)
- 应用程序性能测试的艺术(连载)第2章 有效应用系统性能测试的基本原则02
- 让你的笔记本更快一点——我的笔记本的性能测试和虚拟硬盘(把内存当成硬盘)的使用感觉
- Linux下用JMap对Java程序进行性能测试检查内存泄露问题
- 使用开源的Profiler来测试你的Java应用程序的性能