【操作系统】Linux程序内存结构&内存分配
对于一个32位的linux操作系统,他的进程内存分布如下图:
- 低地址从0x00000000开始
- 高地址到0xFFFFFFFF
代码区:
存放程序执行代码的一段内存,内存区域只读,并且在代码段中可能也包含一些只读常量。
数据区
分为已初始化数据区 (.data)和未初始化数据区(BSS),分别用来存放已经初始化的全局变量和静态变量和未初始化的全局变量和静态变量。
其中BSS不占据目标文件大小,因为数据没初始化。系统调用exec将程序装载进内存时,将他们设置为0…data段因为已经初始化,数据保存在目标文件中
疑问? 如果bss段不占内存,那变量名存在哪?
目标文件在运行时多出来两个区域,堆区和栈区(不多赘述)
64位机器栈区大小应该是8M(可通过shell命令ulimit -s 查看)
堆区内存分配
C语言中的malloc底层通过两个系统调用来分配内存
- brk
- mmap
结论:在分配的内存小于128K时,使用brk分配内存,当分配内存大于128K时,使用mmap。
当分配的内存小于128K时,在进程内存里面存在着一个_edata指针,每次分配多少内存,指针就会移动多少。见下图
第一次分配30K,指针向高地址移动30K大小的内存,第二次分配40K同理。如图中的B,C
上图分配200K的空间,会调用mmap插入一段进去 如图A
brk在分配B, C之后,如果此时free C ,那么C这一块内存将不会被释放掉,因为B还没有被释放(内存碎片产生的原因)
mmap则不会,A所在内存释放之后,内存会立即被回收。
那么brk分配的内存什么时候被释放呢?
紧缩 trim:紧缩指的是,当brk分配的内存,有超过128K的内存被释放时,实际的内存才会真正被释放。
举个例子:上图分配了B,和C 共70K,假设此时又分配了70K;如果从此时到这140K内存都被释放,系统监测到_edata下面有超过128K内存了,就会执行紧缩操作,释放系统中的这140K的内存。
缺页中断
程序申请内存之后,物理内存并不会被立即被分配,当程序真正使用的时候,才会建立与物理内存的映射,即缺页中断。
一般缺页中断会进行以下操作
- 1 检查虚拟内存是否合法
- 2 查找/分配一个物理页
- 3 填充物理页内容(置0或者啥也不干)
- 4 建立虚存到物理内存的映射
然后重新执行发生了缺页中断的那条指令。
在发生缺页中断时如果进行了第三步,被称为majflt(大中断),如果没有被称为minflt(小中断)。
可以用ps -o majflt, minflt -C program
查看