什么时候为进程分配内存 什么是内存( 二 )


1 .在压力试验过程中,发现被试对象的性能不够理想 , 具体如下:
进程的系统CPU消耗是20 , 用户CPU消耗是10,系统空闲大约是70
2 ps -o majflt , minflt -C程序命令显示majflt每秒增量为0,而minflt每秒增量大于10000 。
初步分析
Majflt代表major fault , 中文叫大错误,minflt代表minor fault,中文名字叫小错误 。
这两个值表示自进程启动以来在进程中发生的缺页中断的数量 。
当进程被页面错误中断时,该进程将进入内核状态并执行以下操作:
检查要访问的虚拟地址是否合法 。
查找/分配物理页面
填充物理页面内容(读取磁盘,或者直接设置为0 , 或者什么都不做)
建立映射关系(虚拟地址到物理地址)
使用页面错误中断重新执行指令 。
第三步,如果需要读磁盘,那么这个缺页中断就是majflt,否则就是minflt 。
这个进程的minflt这么高,一秒一万多次,我们不得不怀疑和进程的内核cpu消耗有很大关系 。
分析代码
看代码,发现是这样写的:一个请求来了,用malloc分配2M内存,请求结束后释放这个内存 。查看日志 , 发现分配内存的语句需要10us,一个请求的平均处理时间是1000us 。原因已经找到了!
尽管内存分配语句在处理请求时花费的时间很少,但它会严重影响性能 。要解释清楚原因,首先需要知道内存分配的原理 。
这个案子已经完全澄清了 。
在谈到内存分配的原理之后,被测试模块在内核状态下cpu消耗高的原因就很清楚了:malloc在每次请求到来时都有一个2M内存 。默认情况下,malloc调用mmap来分配内存,当请求完成时 , 它调用munmap来释放内存 。假设每个请求需要6个物理页面 , 每个请求将产生6个缺页中断 。在2000的压力下,每秒有超过10000个缺页中断 。这些缺页中断不需要通过读盘来解决,所以称为minflt页面中断是在内核态执行的,所以进程的内核态cpu消耗很大 。页面中断分散在请求的整个处理过程中,因此它表明分配语句时间(10us)与整个请求的处理时间(1000us)相比非常小 。
解决办法
【什么时候为进程分配内存 什么是内存】将动态内存改为静态分配,或者在启动时 , 用malloc分配给各个线程,然后保存在threaddata中 。但是由于这个模块的特殊性,静态分配或者启动分配都是不可行的 。另外,Linux下默认栈的大小限制是10M , 所以在栈上分配几米内存是有风险的 。
禁止Malloc调用mmap分配内存,禁止内存收缩 。
当该过程开始时,添加以下两行代码:
mall opt(M _ MMAP _马克斯,0);//禁止malloc调用mmap分配内存
mallopt(M_TRIM_THRESHOLD,-1);//禁止内存压缩 。
效果:添加这两行代码后,用ps命令观察 。压力稳定后,majlt和minflt都为0 。进程的系统状态cpu从20下降到10 。
总结
您可以使用命令ps -o majflt,minflt -C程序来查看进程的majflt和minflt的值 。这两个值是累积值,从过程开始时累积 。当对具有高性能需求的程序进行压力测试时,我们可以将这两个值相加 。
如果一个进程使用mmap将一个大的数据文件映射到进程的虚拟地址空,我们需要重点关注majflt的值,因为与minflt相比,majflt对性能是致命的,随机读取磁盘需要几个毫秒,而minflt只有在数量很多的情况下才会对性能产生影响 。

推荐阅读