专栏首页腾讯移动品质中心TMQ的专栏win32应用程序性能测试-内存篇

win32应用程序性能测试-内存篇

本文主要讲述windows平台下应用程序性能测试的内存相关的知识,通过本文了解内存基本原理和分析内存占用问题。

一、内存是什么?

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 list

HardPageFault:访问的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刷内存

刷内存SetProcessWorkingSetSize

1原理

函数用来设置应用程序最小和最大的运行空间,只会保留需要的内存,例如我们的部分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(gh_2052d3e8c27d),作者:dorahe

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-01-03

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【 Android 场景化性能测试】内存性能及内存泄漏篇

    承接《Android场景化性能测试-方向与框架篇》,本篇详述内存性能的具体测试方案和内存泄漏问题简单定位方法。

    腾讯移动品质中心TMQ
  • 内存泄漏漫谈

    对于C/C++来说,内存泄漏问题一直是个很让人头痛的问题,因为对于没有GC的语言,内存泄漏的概率要比有GC的语言大得多,同时,一旦发生问题,也严重的多,而且,内...

    腾讯移动品质中心TMQ
  • 腾讯TMQ在线沙龙|android内存性能测试

    Android内存性能测试 活动时间:2016年10月31日 QQ群视频交流 活动介绍:TMQ在线沙龙第十一期分享 本次分享的主题是老司机给大家分享androi...

    腾讯移动品质中心TMQ
  • iOS标准库中常用数据结构和算法之内存池

    内存池提供了内存的复用和持久的存储功能。设想一个场景,当你分配了一块大内存并且填写了内容,但是你又不是经常去访问这块内存。这样的内存利用率将不高,而且无法复用。...

    欧阳大哥2013
  • 经典面试题(一)之服务器内存碎片

    年前去过上海掌门集团(做无线wifi万能钥匙的那一家)和百度面试过一次,前者问了linux下gcc的malloc函数如何分配内存的,后者在二面时通过一个链表的数...

    范蠡
  • 【编程基础】C语言内存使用的常见问题

    所讨论的“内存”主要指(静态)数据区、堆区和栈区空间。数据区内存在程序编译时分配,该内存的生存期为程序的整个运行期间,如全局变量和static关键字所声明的静态...

    程序员互动联盟
  • 【编程基础】什么是内存泄露

    内存泄漏也称作“存储渗漏”,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之...

    程序员互动联盟
  • 内存溢出和内存泄漏

    通俗的讲就是设备内存不够了。就好比我们的手机,运行内存是4G的,当我们运行了太多的程序时,在运行其他的软件时就会很卡或者提示xx运行停止。

    卡二条的技术圈子
  • 聊一聊内存管理(一)

    在我们的日常生活中,经常会遇到这样的对话。当电脑运行程序变得很慢很卡的时候,就会听到身边的朋友建议我们去增加电脑的内存。这是为什么呢?内存在计算机体系结构中起了...

    算法与编程之美
  • Linux之《荒岛余生》(三)内存篇

    内存问题,脑瓜疼脑瓜疼。脑瓜疼的意思,就是脑袋运算空间太小,撑的疼。本篇是《荒岛余生》系列第三篇,让人脑瓜疼的内存篇。其余参见:

    xjjdog

扫码关注云+社区

领取腾讯云代金券