一、引子
作者、我在上班闲着没事的时候,看了一些关于Linux内存管理和程序装载、链接的文章,然后自己就总结出了一些东西。
本系列文章一方面将资料中的长篇大论总结到最少、以方便可以直接找到答案,一方面也是方便面试的时候可以吹牛逼。
Linux的内存管理模块是Linux内核中最复杂、最大的一块了。本系列将分为四方面来讲述:
1.程序在内存中分区,
2.ELF文件如何装载、加载,
3.内存管理的硬件架构分类,
4.内存空间管理。
二、内存分类
首先要先了解内存有几种,才能更好的了解内存管理。
1.物理内存
物理内存(Physical memory)是相对于虚拟内存而言的。物理内存指通过物理内存条而获得的内存空间。
常见的物理内存规格有2G、4G等,现如今随着计算机硬件的发展,已经出现8G、16G甚至更高容量的内存规格。
在应用中,自然是顾名思义,物理上,真实存在的插在主板内存槽上的内存条的容量的大小。
看计算机配置的时候,主要看的就是这个物理内存。
2.虚拟内存虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。大多数操作系统都使用了虚拟内存,如Windows家族的“虚拟内存”;Linux的“交换空间”等。
本系列文章的前两方面如无特殊说明都是说虚拟内存。
三、程序在内存中分区
计算机按CPU位数不同可分为8位系统、32位系统、64位系统。本次介绍目前最常用的32位和64位系统的内存分区。
虚拟内存又分为用户态内存和内核态内存。
3.1用户态内存
3.1.1 32位系统
32位理论上最大能够使用的内存是4GB。其中3-4G地址是内核态内存,是系统内核使用的内存。0-3G是用户态内存,这是程序员可以使用的内存。
在使用PAE技术(Physical Address Extension)后,32位系统可以支持最多64GB的物理内存,但是每个进程的地址空间仍然只有4GB,而且需要硬件和驱动的支持。PAE意思是物理地址扩展,它是一种让32位系统能够识别和使用超过4GB的物理内存地址的技术。
1.程序运行前在二进制文件中的机器码会被加载到内存中,放这些机器码的空间就是代码段。
2.程序运行前会将程序中全局变量和静态变量根据ELF文件加载进内存。
有初始值的全局变量和静态变量会放在数据段。这个时候这些变量已经有数据了。
没有初始值的全局变量和静态变量会放在BSS段。这个时候这些变量会在加载进内存时被初始化为0。
这三个段的内存是在程序编译期间就已经确定的。
3.程序运行中程序员向系统动态申请的内存,会放在堆。
地址增长方向是从低地址到高地址增长。
4.动态链接库的内容和mmap映射出的共享内存空间是存放在文件映射和匿名映射区。
地址增长方向是从高地址到低地址增长。
程序运行中依赖的动态链接库,会以.so文件放在磁盘里。这些文件的数据段、代码段、BSS段等也会加载进内存。
系统调用mmap进行内存和文件的映射。
5.程序运行中调用的函数、使用的局部变量和函数入参,将放入栈。
地址增长方向是从高地址到低地址增长。
6.在用户态中还有一块不能被使用的内存地址,被称为保留区。
这块区域一般是不允许被访问的,地址是从0x0000 0000 到0x0804 8000,所以会将无效的指针指向NULL。
7.未分配区域有两块在栈和文件映射和匿名映射区之间,堆和文件映射和匿名映射区之间。
未分配区域是为了让堆能继续向上申请和栈向下使用能留有足够空间。
如图:
3.1.2 64位系统
64位理论上最大能够使用的内存是2的64次方字节,但在目前的Linux上只使用了2的48次方字节来描述内存,也就是现在有256TB的内存空间。系统在理论空间中将最高的128T作为内核态空间,最低的128T作为用户态空间。
我找到的资料和系统都是按48次方寻址的,还有一种说法现在已经可以真实描述更多的内存空间。但我未找到相应的系统。大家可以使用命令去查看你的系统内存分布情况,看有没有比48位还要多的。
cat /proc/pid/maps
pmap pid
64位系统和32位系统内存分布大致相同,下面仅介绍不同点
1.在用户态和内核态间有一块不能被使用的内存地址,被称为canonical address空洞。
用户态的空间是128T,所以最高的地址是0X0000 7FFF FFFF FFFF.它的高16位全为0。
内核态的空间也是128T,所以最低的地址是0XFFFF 8000 0000 0000.它的高16位全为1。
在这两个中间的高16位既不全为1又不全为0的地址被称为canonical address空洞。
用户态空间和内核态空间称为canonical address。