C++应用程序性能优化——操作系统内存管理

来源:互联网 发布:脐橙淘宝店铺装修图 编辑:程序博客网 时间:2024/05/22 14:12

1. 工作集:

概念:操作系统中驻留在物理内存中的内存页成为进程的工作集。



工作集的大小:

操作系统为每个进程定义了最小工作集(20-50MB),和最大工作集(45-345MB)(具体与系统的物理内存大小有关)


工作集的增长:

当执行到未被调入内存的代码页或数据页时,这些页会被调入内存,工作集随之增长。

当工作集达到最大工作集,进程需要再次调入新页到物理内存时,虚拟内存管理器会将原来工作集中某些页置换出内存,把需要调入的新页调入内存


访问内存的性能:

工作集中的内存驻留在物理内存中,因此对其中的内存访问不涉及系统IO,速度比较快;如果访问的内存不在工作集中,需要额外的IO,效率比较低。


基于工作集的内存优化:

操作系统调入需要的页,会将该页及其附近的页一起调入内存

基于以上逻辑,代码优化可考虑以下处理:

(1) 尽量编写紧凑代码:

根据locality特性,以前执行的代码和访问的数据很有可能在后面再次执行和访问,这样程序运行时发生的缺页错误大大降低,即减少了磁盘IO。

(2)尽量把需要一起访问的数据放在一起

这样访问这些数据时,它们在同一页或相邻页上,可以降低缺页错误。


2. 内存映射文件

相关API:CreateFileMapping / MapViewOfFile

应用:exe或dll的映射;进程间共享内存

优点:

(1)可以方便的访问硬盘文件,而不用经过繁琐的I/O,效率也会比较高

(2)可以在多个进程间进行共享内存


调页文件:

WIN32中用来辅助实现虚拟内存的硬盘文件称为调页文件。

调页文件存放被虚拟内存管理器置换出内存的数据,当这些数据被再次调用时,虚拟内存管理器会将其从调页文件再次换入内存。

出于空间利用率和性能考虑,程序代码(exe和dl)不会被修改,所以当它所在的页被置换出内存时,不会存放到调页文件,而是直接抛弃;当需要再次调入,虚拟内存管理器会从exe或dll文件中找到它们并重新调入。

结论exe和dll的虚拟内存,通过CreateFileMapping 映射到文件本身(即映射到的物理存储器是文件本身),而不会使用额外的调页文件


3. 进程的内存布局


如图,高位是系统内核使用的内存;剩下的内存从低位到高位依次是:代码区,数据区,堆,栈

代码区:存放程序的机器代码,代码区是只读的,且大小固定。如果试图修改该区域的内容,会引发错误;

数据区:分为两部分DATA(初始化的数据),BSS(未初始化的数据)。DATA和BSS中都包含前面提到的静态/全局数据,常量数据。大小固定。


DATA和BSS的区别:

已初始化的数据是指,编译时就知道初始值的全局和静态变量等,这些初始值必须保存在最终生成的二进制文件中,并在程序运行时会原封不动的映射到进程的初始化数据区域未初始化的数据,并不会保存在二进制文件中,而是在二进制文件中保存一个4字节的值,表明这些数据需要的内存大小。这样的好处是可以让生成的二进制文件更小

例如:一个程序代码100K, 已初始化的数据100K,未初始化数据150K,那么生成的二进制文件中:最开始是100K代码,接着100K已初始化数据,再接着4字节的值,其值为1024*150。 而程序运行时,系统会读取该值,并为其开辟150K的虚拟地址空间。




0 0