Linux系统内存管理

1. 基本概念

1.1 地址

(1)逻辑地址:指由程序产生的与段相关的偏移地址部分。在C语言指针中,读取指针变量本身值(&操作),实际上这个值就是逻辑地址,它是相对于你当前进程数据段的地址。

(2)线性地址:段中的偏移地址(逻辑地址),加上相应段的基地址就生成了一个线性地址。

(3)物理地址: 放在寻址总线上的地址。

(4)虚拟地址:保护模式下段和段内偏移量组成的地址,而逻辑地址就是代码段内偏移量,或称进程的逻辑地址。

1.2 内存

(1) 虚拟内存:计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。与没有使用虚拟内存技术的系统相比,使用这种技术的系统使得大型程序的编写变得更容易,对真正的物理内存(例如RAM)的使用也更有效率。

(2) 物理内存:实际的内存。物理地址被分成离散的单元,成为页(page)。目前大多数系统的页面大小都为4k。

1.3 地址转换

Linux采用段页式管理机制,有两个部件用于地址转换:分段部件和分页部件。

(1) 分段部件:将逻辑地址转换为线性地址。分段提供了隔绝各个代码、数据和堆栈区域的机制,因此多个程序(任务)可以运行在同一个处理器上而不会互相干扰。

(2) 分页部件:将线性地址转换为物理地址(页表和页目录),若没有启用分页机制,那么线性地址直接就是物理地址。

2. 内存分配

Malloc,kmalloc 和vmalloc区别?

(1) kmalloc和vmalloc是分配的是内核的内存,malloc分配的是用户的内存。

(2) kmalloc保证分配的内存在物理上是连续的,vmalloc保证的是在虚拟地址空间上的连续。

(3) kmalloc申请的内存比较小,一般小于128 K。它是基于slab(内存池)的,以加快小内存申请效率。

3. 常见问题

(1) 调用malloc函数后,OS会马上分配实际的内存空间吗?

答:不会,只会返回一个虚拟地址,待用户要使用内存时,OS会发出一个缺页中断,此时,内存管理模块才会为程序分配真正的内存。

(2) 段式管理和页式管理的优缺点?

在段式存储管理中,将程序的地址空间划分为若干个段(segment),这样每个进程有一个二维的地址空间,相互独立,互不干扰。程序通过分段划分为多个模块,如代码段、数据段、共享段。这样做的优点是:可以分别编写和编译源程序的一个文件,并且可以针对不同类型的段采取不同的保护,也可以按段为单位来进行共享。段式存储管理的优点是:没有内碎片,外碎片可以通过内存紧缩来消除;便于实现内存共享。

在页式存储管理中,将程序的逻辑地址空间划分为固定大小的页(page),而物理内存划分为同样大小的页框(pageframe)。程序加载时,可将任意一页放人内存中任意一个页框,这些页框不必连续,从而实现了离散分配。这种管理方式的优点是,没有外碎片,且一个程序不必连续存放。这样就便于改变程序占用空间的大小。

页式和段式系统有许多相似之处。比如,两者都采用离散分配方式,且都通过地址映射机构来实现地址变换。但概念上两者也有很多区别,主要表现在: [1] 页是信息的物理单位,分页是为了实现离散分配方式,以减少内存的外零头,提高内存的利用率。或者说,分页仅仅是由于系统管理的需要,而不是用户的需要。段是信息的逻辑单位,它含有一组其意义相对完整的信息。分段的目的是为了更好地满足用户的需要。

[2] 页的大小固定且由系统决定,把逻辑地址划分为页号和页内地址两部分,是由机器硬件实现的。段的长度不固定,且决定于用户所编写的程序,通常由编译系统在对源程序进行编译时根据信息的性质来划分。

[3] 页式系统地址空间是一维的,即单一的线性地址空间,程序员只需利用一个标识符,即可表示一个地址。分段的作业地址空间是二维的,程序员在标识一个地址时,既需给出段名,又需给出段内地址。

(3) Malloc在什么情况下调用mmap?

从操作系统角度来看,进程分配内存有两种方式,分别由两个系统调用完成:brk和mmap(不考虑共享内存)。brk是将数据段(.data)的最高地址指针_edata往高地址推,mmap是在进程的虚拟地址空间中(一般是堆和栈中间)找一块空闲的。这两种方式分配的都是虚拟内存,没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系。

在标准C库中,提供了malloc/free函数分配释放内存,这两个函数底层是由brk,mmap,munmap这些系统调用实现的。

默认情况下,malloc函数分配内存,如果请求内存大于128K(可由M_MMAP_THRESHOLD选项调节),那就不是去推_edata指针了,而是利用mmap系统调用,从堆和栈的中间分配一块虚拟内存。这样子做主要是因为brk分配的内存需要等到高地址内存释放以后才能释放(例如,在B释放之前,A是不可能释放的),而mmap分配的内存可以单独释放。

(4) 32位系统,通常情况下,最大虚拟地址和物理地址空间为多少?

不使用PAE情况下,最大虚拟地址和物理地址空间均为4G,若果使用PAE,最大虚拟地址仍为4G,而物理地址空间可变为64G(x86, 32为变36位)。

(5) 怎样实现malloc和free?

Malloc实现可考虑采用buddy算法+slob算法,free类似。

4. 参考资料

Linux Memory Management Notes:

http://vmlinz.is-programmer.com/posts/26540.html

内存段页式管理笔记:

http://chenxu.yo2.cn/articles/linux_memory.html

虚拟地址、线性地址和物理地址的转换:

http://dogking.chinaunix.com/space.php?uid=23208702&do=blog&id=163527

kmalloc、vmalloc、malloc的区别:

http://blog.csdn.net/macrossdzh/article/details/5958368

Linux中的物理和虚拟存储空间布局:

http://book.chinaunix.net/showart.php?id=3266

[百度分享]频繁分配释放内存导致的性能问题的分析

http://topic.csdn.net/u/20100325/16/0b86c0ed-5b8d-4eec-a757-c782ae9a3a35.html

5. 后记

最近面试常被问到内存管理的一些基础知识,特整理此文,以作为这阶段面试的小总结。

posted @ 2012-04-27 22:07  dancingrain  阅读(251)  评论(0编辑  收藏  举报