《程序员的自我修养》读书笔记5 -- 内存
2014-11-08 15:46
134 查看
一、进程的内存布局
一般来讲进程有如下默认区域:
栈:用于维护函数调用上下文,通常从用户空间高地址开始向低地址增长;
堆:进程动态分配内存区域,一直存在直到被手动回收或者进程结束;
可执行文件和共享对象镜像:
保留区:内存中受保护而禁止访问区域,访问该处会出现段错误,通常靠近0x0处。比如int *p = NULL就是无效指针。
其中栈和堆是我们主要需要分析的部分。
二、栈和惯例
栈的布局如下图。
函数调用过程:
调用方需要做的事情:
(1)将参数压入栈 (2)将当前指令下一条指令地址压入栈 (3)跳转到被调函数体; 其中(2)(3)两步通过call函数一起执行。
被调函数首先需要做的事情:
push %ebp 将old ebp压入栈中
mov %esp %ebp 将新的ebp指向栈顶
sub %esp XXX 分配新的临时栈空间
push XXX 将一些需要保存寄存器压栈
被调函数结束时则进行相反的过程。
调用惯例:
函数调用方和被调方共同遵守的约定,使函数能够正确被调用。主要有以下几方面内容:
函数参数的传递顺序:即多个参数的压栈顺序
栈的维护方式,比如函数调用结束,由谁来弹出栈中函数参数
名字修饰策略:调用惯例需要对函数本身名字进行修饰
cdecl是C语言中默认调用惯例,内容如下:
函数返回值参数传递:
函数可以将返回值存储在寄存器中。对于返回值5~8字节情况,一般通过eax和edx联合返回方式进行。
如果是返回对象很长的情况。。。
(1)调用方使用临时栈上空间作为中转,并将此区域首指针作为隐含参数传递给被调方;
(2)被调方根据该隐含参数,将返回对象拷贝给中转区域;
(3)调用方将中转区域拷贝给最终对象。
三、堆和内存管理
Linux进程堆管理
Linux提供两种堆空间分配方式:
int brk(void *end_data_segment) 实际作用是扩大或缩小数据段,若我们将数据段结束地址向高端地址移动,则扩大的空间将作为堆空间,这是最常用的做法之一。
void mmap(*start, length, prot,flags,...) 指定需要申请的地址大小和长度,都是页的整数倍。
glibc中malloc()函数是处理用户空间请求:小于128k请求,在现有堆空间里,按照堆分配算法分配空闲块;对于大于128k请求,直接通过mmap()分配一块匿名空间。
堆分配算法
如何管理一大块连续的内存空间,能够按照需求分配,释放其中的空间。
空闲链表法:将整个堆空间中,空闲的块通过链表方式链接,用户请求空间时,遍历链表找到合适空闲块,并对块进行拆分(用户请求部分和剩余空闲部分),并更新链表里空闲块。用户释放时将他合并至空闲链表中。
位图:将整个堆划分成大量的块,每个块大小相同。用位图记录所有块的使用情况。
对象池
一般来讲进程有如下默认区域:
栈:用于维护函数调用上下文,通常从用户空间高地址开始向低地址增长;
堆:进程动态分配内存区域,一直存在直到被手动回收或者进程结束;
可执行文件和共享对象镜像:
保留区:内存中受保护而禁止访问区域,访问该处会出现段错误,通常靠近0x0处。比如int *p = NULL就是无效指针。
其中栈和堆是我们主要需要分析的部分。
二、栈和惯例
栈的布局如下图。
函数调用过程:
调用方需要做的事情:
(1)将参数压入栈 (2)将当前指令下一条指令地址压入栈 (3)跳转到被调函数体; 其中(2)(3)两步通过call函数一起执行。
被调函数首先需要做的事情:
push %ebp 将old ebp压入栈中
mov %esp %ebp 将新的ebp指向栈顶
sub %esp XXX 分配新的临时栈空间
push XXX 将一些需要保存寄存器压栈
被调函数结束时则进行相反的过程。
调用惯例:
函数调用方和被调方共同遵守的约定,使函数能够正确被调用。主要有以下几方面内容:
函数参数的传递顺序:即多个参数的压栈顺序
栈的维护方式,比如函数调用结束,由谁来弹出栈中函数参数
名字修饰策略:调用惯例需要对函数本身名字进行修饰
cdecl是C语言中默认调用惯例,内容如下:
函数返回值参数传递:
函数可以将返回值存储在寄存器中。对于返回值5~8字节情况,一般通过eax和edx联合返回方式进行。
如果是返回对象很长的情况。。。
(1)调用方使用临时栈上空间作为中转,并将此区域首指针作为隐含参数传递给被调方;
(2)被调方根据该隐含参数,将返回对象拷贝给中转区域;
(3)调用方将中转区域拷贝给最终对象。
三、堆和内存管理
Linux进程堆管理
Linux提供两种堆空间分配方式:
int brk(void *end_data_segment) 实际作用是扩大或缩小数据段,若我们将数据段结束地址向高端地址移动,则扩大的空间将作为堆空间,这是最常用的做法之一。
void mmap(*start, length, prot,flags,...) 指定需要申请的地址大小和长度,都是页的整数倍。
glibc中malloc()函数是处理用户空间请求:小于128k请求,在现有堆空间里,按照堆分配算法分配空闲块;对于大于128k请求,直接通过mmap()分配一块匿名空间。
堆分配算法
如何管理一大块连续的内存空间,能够按照需求分配,释放其中的空间。
空闲链表法:将整个堆空间中,空闲的块通过链表方式链接,用户请求空间时,遍历链表找到合适空闲块,并对块进行拆分(用户请求部分和剩余空闲部分),并更新链表里空闲块。用户释放时将他合并至空闲链表中。
位图:将整个堆划分成大量的块,每个块大小相同。用位图记录所有块的使用情况。
对象池
相关文章推荐
- 《程序员的自我修养-链接加载与库》读书笔记(2)---程序环境-内存
- 内存、栈、堆的一点小总结 《程序员的自我修养》·笔记
- delphi 精要-读书笔记(内存分配释放)
- 【程序员的自我修养】第10章 内存
- javascript高级程序设计(第3版) 读书笔记2 变量,作用域 内存问题
- 移动APP性能测评与优化读书笔记-1.1 内存分析
- 《疯狂Java:突破程序员基本功的16课》读书笔记-第一章 数组与内存控制
- 《深入理解Linux内核》读书笔记-第二章-内存寻址(1)
- [读书笔记]程序员的自我修养(2)
- 《深入理解Linux内核》读书笔记-第二章-内存寻址(2)
- 读书笔记-SQL Server 数据页缓冲区的内存瓶颈分析
- 【读书笔记:C++ primer plus 第六版 中文版】第9章 内存模型和名称空间
- 《JavaScript高级程序设计》读书笔记--4-变量、作用域和内存问题
- 错误内存【读书笔记】C程序中常见的内存操作有关的典型编程错误
- 《javascript高级编程》读书笔记(三)变量、范围和内存的问题
- 推荐:《程序员的自我修养——链接、装载与库》 读书笔记
- 《深入理解java虚拟机》读书笔记一 【java内存区域】
- Sql Server内存瓶颈(读书笔记)
- 《读书笔记》程序员的自我修养之线程安全问题
- 读书笔记之: 程序员的自我修养——链接,装载与库(第3,4部分)