《C++应用程序性能优化》内存管理篇笔记(一)

    Win32  

    进程私有:只能访问属于自己的4GB虚拟地址空间(父子进程例外,比如调试器利用父子进程关系来访问被调试进程的地址空间)。Dll本身没有属于自己的虚拟地址空间,而是其所属进程的虚拟地址空间,Dll的全局数据以及通过Dll函数申请的内存都是从调用其进程的虚拟地址空间中开辟。

    基于页:是指虚拟地址空间被划分为多个称为“页”的单元,页的大小由底层处理器决定,x86中的页大小为4KB。页是Win32虚拟内存管理器处理的最小单元,相应的物理内存也被划分为多个页。虚拟内存地址空间的申请和释放,以及内存和磁盘的数据传输或置换都是以页为最小单位进行的。

    4GB:进程中的地址取值范围可以从0x00000000到0xFFFFFFFF。Win32将低区的2GB留给进程使用,高区的2GB则留给系统使用。

    调页文件:用来辅助实现虚拟内存的硬盘文件称为“调页文件”,可以有16个。出于空间利用效率和性能的考虑,程序代码(包括exe和dll文件)不会被修改,所以当它们所在的页被置换出内存时,并不会被写进调页文件,而是直接抛弃。当再次被需要时,虚拟内存管理器直接从存放它们的exe或dll文件中找到它们并调入内存。

    缺页错误:当进程执行某段代码或者访问某些数据,而这些代码或者数据还没有在内存时,这种情形称为“缺页错误”。

    在进程 虚拟地址空间中的页有3种状态:自由(free),预留(reserved)和提交(committed)。

    1)自由:此页尚未被分配,可用来满足新的内存分配请求。

    2)预留:指从虚拟地址空间中划分一块区域(region,页的整数倍数大小),划出之后这个区域中的页不能用来满足新的内存分配请求,而是用来供要求“预留”此段区域的代码以后使用。预留时并没有分配物理存储,只是增加了一个描述进程虚拟地址空间使用状态的数据结构(VAD,虚拟地址描述符),用来记录这段区域已被预留。“预留”操作相对较快,因为没有真正分配物理内存。也正因为没有分配真正的物理存储,所以预留的空间并不能够直接访问,对预留的空间并不能够直接访问,对预留页的访问会引起“内存访问违例”(内存访问违例会导致整个进程立刻退出,而不仅仅是中止引起该违例的线程)。

    3)提交:若想得到真正的物理存储,必须对预留的内存进行提交。提交会从调页文件中开辟空间,并修改VAD中的相应项。注意,提交时也并没有立刻从物理内存中分配空间,而只是从磁盘的调页文件中开辟空间。这个空间用做以后置换的备份空间,直到有代码第一次访问这段提交内存中的某些数据时,系统发现并没有真正的物理内存,抛出缺页错误。虚拟内存管理器处理此缺页错误,直到这时才会真正分配物理内存,提交也可以在预留的同时一起进行。需要注意的是,提交操作会从调页文件中开辟磁盘空间,所以比预留操作的时间长。

    想想,为什么要用预留及提交机制?如果只是随需分配内存来满足每次的请求,那么对一个会在不同时间点频繁请求内存的代码来说,因为在它请求内存的不同时间点的间隙极有可能会有其他代码请求内存。这样这段在不同时间点频繁请求内存的代码请求得到的内存因为虚拟地址不连续,无法很好地利用空间的locality特性,对其整体进行访问(比如遍历操作)时就会增加缺页错误的数量,从而降低程序的性能。

    线程栈的预留及提交机制:线程栈的默认大小是1MB(此选项可在CreateThread或在链接时通过链接选项修改,理论上用户最多可创建2G/1M=2048个线程),初始时只有前两页是提交的。当线程栈因为函数的嵌套调用需要更多的提交页时,虚拟内存管理器会动态地提交该虚拟地址区域中的后续页以满足其需求,直到到达1MB的上限。当到达此预留区域大小的上限(默认1MB)时,虚拟内存管理器不会增加预留区域大小,而是在提交最后一页时抛出一个栈溢出异常,抛出栈溢出异常时该栈还有一页空间可用,程序仍可正常运行。而当程序继续使用栈空间,用完最后一页后,还继续需要存储空间,这时就超过了上限,会直接导致进程退出。

    所以为防止线程栈溢出导致整个程序退出,应该注意尽量控制栈的使用大小。比如减少函数的嵌套层数,减少递归函数的使用,尽量不要在函数中使用太大的局部变量(大的对象可以从堆中开辟空间存放,因为堆会动态扩大,而线程栈的可用内存区域在线程创建时就已固定,之后在整个线程生命期间无法扩展)。

    另外为了防止因为一个线程栈的溢出导致整个进程退出,可以对可能会产生线程栈的溢出的线程体函数加异常处理,捕获在提交最后一页时抛出的溢出异常,并做出相应处理。

    访问虚拟内存时的处理流程:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值