内存——程序员的自我修养读书笔记(1)

平坦(flat)内存模型:应用程序使用物理地址进行寻址。
内核空间:Windows下高地址的2GB,Linux下高地址的1GB。
用户空间:内存中内核空间外的空间。分为栈、堆、可执行文件映像,保留区,详见p285。


用于维护函数调用的上下文,通常分配在用户空间的最高地址处,有数兆字节大小。
在计算机系统中,栈是一个具有先进后出(first in last out)属性的动态内存区域,向下增长。
栈保存了一个函数调用所需要的维护信息,称为栈帧(Stack Frame)或活动记录(Activate Record),该结构包含函数的返回地址和参数,临时变量(非静态局部变量和编译器生成的临时变量),保存的上下文(如函数调用前后保持不变的寄存器)。
小知识:微软编译器会将栈空间中的字节初始化为0xCC,而0xCCCC的汉字编码就是“烫”,因此若直接输出的话,会看到:烫烫烫烫烫烫烫烫。有的也使用0xCD来初始化,这时看到的是“屯”。
调用惯例:函数的调用方和被调用方都遵守的约定。主要包含:函数参数的传递顺序和方式(栈或寄存器,从左到右或从右到左),栈的维护方式,名字修饰(name-mangling)的策略。如C语言默认的调用惯例是cdecl,其它的调用惯例有stdcall、fastcall、pascal等。
函数返回值传递的流程:1.临时开辟一段栈空间用于保存返回值。2.将结果拷贝到这段空间中。3.将栈空间中的临时对象拷贝到返回值的对象里。因此在不进行优化的情况下C++返回对象要进行两次拷贝,开销很大。目前已使用一种叫做返回值优化(RVO)的技术进行改进。


动态分配使用的内存区域,如new或malloc得到的内存都来自堆。堆位于内存的低地址处,一般比栈大很多,有几十至数百字节的容量。
堆分配的系统调用:brk()和mmap()。
brk():扩大或缩小进程数据段(数据段和BSS段的总称)的结束地址。
堆分配算法:空闲链表法、位图、对象池。
空闲链表法:把堆中各个空闲的块以链表的方式连接起来,当用户请求空间时,遍历整个链表,知道找到合适大小的块并将其拆分,当用户释放空间时将其合并到空闲链表中。
位图:将整个堆划分为大量的块,每个块大小相同。当用户请求空间时,总是分配整数个块的空间。在被分配的块里面,第一个称为header,其余的称为body。由于每个块只有3种状态(header/body/free),因此2bit就可以表示一个块,因此称为位图。
对象池:如果每次分配的空间大小都相同,就将这个大小作为单位,把堆划分为大量的小块,每次请求只需找到一个小块就行了。
glibc中对于小于64字节的空间申请使用的是对象池的方式,对于大于512字节使用的是最佳适配算法,对于大于64小于512字节的采取上述方法中的折中策略,对于大于128KB的,用mmap申请。

可执行文件映像:由装载器在装载时将可执行文件的内存读取或映射到这里。
保留区:是对内存中受到保护而禁止访问的内存区域的总称,不是一个单一的内存区域。如大多数操作系统里,极小的地址都是禁止访问的,如NULL,C语言将无效指针赋值为0也是出于这个考虑,因为0地址正常情况下没有有效的可访问数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值