第十章 内存
1. 段错误,segment fault,最普遍的原因:
程序员将指针初始化为NULL,之后却没有给它一个合理的值就开始使用指针。
程序员没有初始化栈上的指针,指针值一般会是随机数,之后就直接开始使用指针。
2. 堆栈,保存活动记录(堆栈帧)
栈底:0xbfffffff, esp寄存器指向栈顶,保存的内容:
函数的返回地址和参数
临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量
保存的上下文:包括的函数调用前后需要保持不变的寄存器
ebp:帧指针,指向函数活动记录的一个固定位置。(返回地址下信息地址)
函数记录结构:
把所有或一部分参数压入栈中,如果有其他参数没有入栈,那么使用某些特定的寄存器传递
把当前指令的下一跳指令的地址压入栈中
跳转导函数体执行
3. 调用惯例
在C语言里默认为cdecl(非标准关键字),在gcc中是__attribute__((cdecl)),参数从右至左顺序压栈,函数调用方完成出栈,名字修饰直接在函数名称前加1个下划线
4. c++返回值优化,因为在c++里返回一个对象的时候,对象要经过2次拷贝构造函数的调用才能够完成返回对象的传送。
5. 堆
系统调用的开销较大
Linux进程堆:brk()和mmap()[系统页大小的整数倍,同windows下的VirtualAlloc]系统调用
windows进程堆:堆管理器 HeapCreate,HeapAlloc,HeapFree,HeapDestroy,默认堆的大小为1M
使用malloc调用会不会用到系统调用或者API,应该看当前进程向操作系统批发的空间够不够用。
堆不是总是向上增长的
不能重复两次释放堆里的同一片内存
malloc申请的内存在进程结束后不会存在
malloc申请的虚拟空间是连续的,申请的物理空间是不一定连续的
堆分配算法:空闲链表,位图,对象池