搞懂Linux内存管理,仅此一篇
内存管理应该是Linux内核中非常重要的子系统,之前一直在构思怎么去写一篇Linux内存管理的文章,由于内容实在过于庞大复杂,要想要通俗易懂而且不丢失专业性的阐述真的是一种考验。了解内管管理的实现原理不管对内核开发人员还是应用程序开发人员来说都帮助极大。本文也致力于用简单生动的语言带领大家认识内存管理的原理,当然也少不了一些理论知识的铺垫。我们的目的不是探讨理论,而是为了更加全面的理解原理,必要时我们会深入理论,窥探理论知识的背后。 进程和内存 我们都知道,进程运行需要内存。它主要是用来存放从存储介质中(磁盘/flash/...)载入的程序代码和进程运行所需要的数据内容。在我的另一篇文章中怎样深入理解堆和栈有对进程的组成讲解。对于一个进程来说都会有5中不同的数据段。
通过程序对内存的不同用途,分为了上述5种不同的段,那这些段在内存是怎样组织的呢?看下图: 从图中我们不难发现,堆栈好像是挨在一起的,他们一个向下“长”(i386体系结构中栈向下、堆向上),一个向上“长”,相对而生。但你不必担心他们会碰头,因为他们之间间隔真的很大。 从用户态向内核态看,我们所使用的内存形式的变化: 逻辑地址经段机制转化成线性地址;线性地址又经过页机制转化为物理地址。(但是我们要知道Linux系统虽然保留了段机制,但是将所有程序的段地址都定死为0-4G,所以虽然逻辑地址和线性地址是两种不同的地址空间,但在Linux中逻辑地址就等于线性地址,它们的值是一样的)。沿着这条线索,我们所研究的主要问题也就集中在下面几个问题。
下面我们就来看看吧。 进程地址空间 现代的操作系统基本是采用虚拟内存管理技术,当然Linux作为先进的os也不例外,每个进程都有自己的进程地址空间。该空间为4G的线性虚拟空间。用户态接触到的都是虚拟地址,根本无法看到物理地址,也不用关心物理地址。利用这种虚拟地址的方式,可以保护内存资源,起到隔离的作用。而且对于用户程序来说,始终是4G的大小,可以在程序编译的时候就能确定代码段地址。我们应该知道三件事情:
进程内存管理 进程内存管理的对象是进程线性地址空间上的内存镜像,这些内存镜像其实就是进程使用的虚拟内存区域(memory region)。进程虚拟空间是个32或64位的“平坦”(独立的连续区间)地址空间(空间的具体大小取决于体系结构)。要统一管理这么大的平坦空间可绝非易事,为了方便管理,虚拟空间被划分为许多大小可变的(但必须是4096的倍数)内存区域,这些区域在进程线性地址中像停车位一样有序排列。这些区域的划分原则是“将访问属性一致的地址空间存放在一起”,所谓访问属性在这里无非指的是“可读、可写、可执行等”。 如果你要查看某个进程占用的内存区域,可以使用命令cat /proc/
每行数据格式如下: (内存区域)开始-结束 访问权限 偏移 主设备号:次设备号 i节点 文件。 注意点:你一定会发现进程空间只包含三个内存区域,似乎没有上面所提到的堆、bss等,其实并非如此,程序内存段和进程地址空间中的内存区域是种模糊对应,也就是说,堆、bss、数据段(初始化过的)都在进程空间中由数据段内存区域表示。 (编辑:ASP站长网) |