- 文件描述符在内核区
- 进程控制块有文件描述符表,文件描述符号表有1024大小数组,其中0,1,2为默认打开的分别表示标准输入,标准输出,标准错误
- 每打开一个新文件,则占用一个文件描述符,而且使用的是最小的一个文件描述符
- 0 - 3G为用户区
- 3G - 4G为内核区
- ELF是linux下可执行文件的文件格式
- ELF段 包括.bss(为初始化全局变量) .dada(已经初始化的全局变量) 其他段(只读数据段,符号段) .text(代码段,二进制机器指令)
- 受保护地址不允许用户访问 #define NULL (void*) 0 在此段
- 动态库在共享库根据相对地址读取,静态库直接在代码段读取
栈(stack)
栈又称堆栈,由编译器自动分配释放,行为类似数据结构中的栈(先进后出)。堆栈主要有三个用途:
- 为函数内部声明的非静态局部变量提供存储空间。
- 记录函数调用过程相关的维护性信息,称为栈帧(Stack Frame)或过程活动记录(Procedure Activation Record)。它包括函数返回地址,不适合装入寄存器的函数参数及一些寄存器值的保存。除递归调用外,堆栈并非必需。因为编译时可获知局部变量,参数和返回地址所需空间,并将其分配于BSS段。
- 临时存储区,用于暂存长算术表达式部分计算结果或alloca()函数分配的栈内内存。
内存映射段(mmap)
- 内核将硬盘文件的内容直接映射到内存, 任何应用程序都可通过Linux的mmap()系统调用或Windows的CreateFileMapping()/MapViewOfFile()请求这种映射。
- 内存映射是一种方便高效的文件I/O方式, 因而被用于装载动态共享库。用户也可创建匿名内存映射,该映射没有对应的文件, 可用于存放程序数据。在 Linux中,若通过malloc()请求一大块内存,C运行库将创建一个匿名内存映射,而不使用堆内存。
- 该区域用于映射可执行文件用到的动态链接库。
堆(heap)
- 堆用于存放进程运行时动态分配的内存段,可动态扩张或缩减。堆中内容是匿名的,不能按名字直接访问,只能通过指针间接访问。
- 分配的堆内存是经过字节对齐的空间,以适合原子操作。
- 堆管理器通过链表管理每个申请的内存,由于堆申请和释放是无序的,最终会产生内存碎片。
- 堆的末端由break指针标识,当堆管理器需要更多内存时,可通过系统调用brk()和sbrk()来移动break指针以扩张堆,一般由系统自动调用。
栈和堆的区别
管理方式:栈由编译器自动管理;
堆由程序员控制,易产生内存泄露。
生长方向:栈向低地址扩展,是连续的内存区域;
堆向高地址扩展,是不连续的内存区域。这是由于系统用链表来存储空闲内存地址,自然不连续,而链表从低地址向高地址遍历。
空间大小:栈顶地址和栈的最大容量由系统预先规定(通常默认2M或10M);
堆的大小则受限于计算机系统中有效的虚拟内存
存储内容:栈在函数调用时,首先压入主调函数中下条指令(函数调用语句的下条可执行语句)的地址,然后是函数实参,然后是被调函数的局部变量。本次调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的指令地址,程序由该点继续运行下条可执行语句。
堆通常在头部用一个字节存放其大小,堆用于存储生存期与函数调用无关的数据,具体内容由程序员安排。
分配方式:栈可静态分配或动态分配。静态分配由编译器完成,如局部变量的分配。动态分配由alloca函数在栈上申请空间,用完后自动释放。
堆只能动态分配且手工释放。
分配效率:栈由计算机底层提供支持:分配专门的寄存器存放栈地址,压栈出栈由专门的指令执行,因此效率较高。
堆由函数库提供,机制复杂,效率比栈低得多。
分配后系统响应:只要栈剩余空间大于所申请空间,系统将为程序提供内存,否则报告异常提示栈溢出。
操作系统为堆维护一个记录空闲内存地址的链表。当系统收到程序的内存分配申请时,会遍历该链表寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点空间分配给程序。若无足够大小的空间(可能由于内存碎片太多),有可能调用系统功能去增加程序数据段的内存空间,以便有机会分到足够大小的内存,然后进行返回。,大多数系统会在该内存空间首地址处记录本次分配的内存大小,供后续的释放函数(如free/delete)正确释放本内存空间。此外,由于找到的堆结点大小不一定正好等于申请的大小,系统会自动将多余的部分重新放入空闲链表中。
- 碎片问题:栈不会存在碎片问题,因为栈是先进后出的队列,内存块弹出栈之前,在其上面的后进的栈内容已弹出。
而频繁申请释放操作会造成堆内存空间的不连续,从而造成大量碎片,使程序效率降低。
- 碎片问题:栈不会存在碎片问题,因为栈是先进后出的队列,内存块弹出栈之前,在其上面的后进的栈内容已弹出。
BSS(Block Started by Symbol)段
- 未初始化的全局变量和静态局部变量
- 初始值为0的全局变量和静态局部变量(依赖于编译器实现)
- 未定义且初值不为0的符号(该初值即common block的大小)
数据段(data)
- 数据段通常用于存放程序中已初始化且初值不为0的全局变量和静态局部变量。数据段属于静态内存分配(静态存储区),可读可写。
代码段(text)
代码段也称正文段或文本段,通常用于存放程序执行代码