转自:http://bbs.chinaunix.net/thread-1925077-1-1.html
经典!看了对低端物理内存和高3
内核的虚拟内存被连续映射到最低端的物理内存。这是所有问题的开始。
为什么要把内核的虚拟地址空间连续地映射到物理内存最低端?这个根本不是个问题。开发人员或是出于效率的原因或是出于实现的原因,就是做了这样的设计。但这种设计却引发了很多令人困惑的问题。
假设我们使用32位版本内核,系统装有2G物理内存,下面所说的“内核的虚拟内存”是指内核前896M虚拟内存。
"内核将自己的虚拟内存连续映射到低端物理内存"到底会产生什么样的结果?是说低端那896M物理内存已被内核所占而不能另做它用?昨天讨论内存的帖子里给出了否定答案,看起来这是个很老的问题了。
书上往往会还有这样的话语:内核只能使用最低端896M物理;超过896M的内存称之为“高端内存”,无法被内核直接使用。初学者读到这里,总觉得哪里不对劲,却又道不出个所以然来。
既然内核已将自己的虚拟内存映射了,内核页表里entries是怎样的呢?在entry中,我们当前感兴趣的有两项:映射地址与Present标志位。映射地址嘛,肯定安排好了。Present标志位是不是1呢?不妨认为是1。这样一来,从内核的页表上来看,前896M的物理内存的的确确被内核所“占用”,只要内核引用相应的虚拟地址,内核就会访问到相应的物理地址,不会发生任何意外。但是,如前面所说,进程也是可以使用这块内存的。如果某个进程的某个虚拟地址映射到了前896M中的某一段,那么内核与进程都可通过各自的页表访问到这块内存。这样会不会发生冲突呢?
描述页帧的数据结构是page结构体,一个页帧是否空闲正是取决于对应page结构体中的引用数。那么内核映射的那896M物理内存是否空闲呢?除了内核代码及静态数据所占的物理页外,其它的全是空闲状态。也就是说《内存管理子系统》可以把这些内存分配出去。昨天帖子里说的“被内核映射了不等于被内核使用了”就是这么回事。内核页表里的内容是说,前896M物理内存处于一种Ready to use的状态,然而没有被内核使用的内存,进程也可以使用。在896M内存中,内核不能使用“被进程使用的内存”,即内核不能引用相应的页表里的内容,即内核不可使用相应的虚拟地址。
内核是怎么使用自己的虚拟地址的呢?她怎么知道哪一段的虚拟地址已经《被自己使用了》或者《因为进程而不能使用》?即内核如何管理自己的虚拟地址。
先看内核如何管理进程的虚拟地址。当进程需要内存时,内核首先会为进程分配一段虚拟地址,即所谓的Memory Region。由于进程虚拟地址的使用情况记录在vm_area_struct中,所有的vm_area_struct都按照顺序连接在一个链表上,因此寻找某大小的虚拟地址十分简单,扫描这个链表,碰到一块大于或等于[所申请内存大小]的连续地址,便用新的vm_area_struct记录下来,并插到链表的合适位置,这块虚拟地址便被标记为“已用”了。其实这就是操作系统理论里所讲的first fit。早期的Unix就是这样管理物理内存的,而这里用之管理进程的虚拟内存。内核为进程分配内存的步骤如下:
一、找到合适大小的虚拟地址段;
二、向{内存管理子系统}申请物理页帧;
三、在进程页表中建立两者的映射关系。
然而内核为<自己>分配内存时,只有#第二步#。
没有第三步,是因为一开始的时候,内核页表已经做好了映射。那第一步呢?内核为什么没有像进程一样<<寻找合适大小的虚拟地址段>>这一步骤?
内核自己需要内存时,总是向Slab层申请(?)。需要创建新的数据结构,需要一个buffer时,Slab便为之分配一块连续的内存。内核不需要对这块内存做映射,只要这块连续的物理内存在前896M之内,它本来就处于一种“预备被内核使用”的状态。从Slab里分出来后,它就“正式被内核使用”。那么说到底,内核怎么管理虚拟地址呢?内核没有“额外管理”,具体使用哪一块虚拟内存取决于Slab分配哪块物理内存。Slab分配哪块物理内存又取决了{内存管理子系统}。{内存管理子系统}={Buddy System}
结论是:Buddy System管理了内核的虚拟内存。严格来说,Buddy System在管理前896M物理内存时随便把内核的虚拟内存也管理了。对进程来说,分配虚拟内存与分配物理内存是分开的步骤;对于内核来说,分配了物理内存就等于分配了虚拟内存。内核为自己分配的内存究竟在虚拟内存的什么位置取决于分[配到的内存的页帧]在物理内存中的哪个位置。进程需要额外的结构体记录虚拟内存的使用的情况;内核虚拟内存的使用情况就是前896M物理内存的使用情况。换句话说,一旦进程申请到了前896M物理内存中的某一块,就相当于侵占了内核的虚拟地址空间,就相当于内核对应的虚拟地址段已经被使用。由于所有对物理内存的申请都由Buddy System应答,内核为自己申请内存时,不可能再获得被[进程占用的物理内存]所对应的[虚拟地址],也就不可能去[引用相应的页表],冲突也就避免了。当然,如果内核有BUG,指针使用不慎,很容易破坏进程的内存。
这样一来,问题都解决了。前896M物理内存由内核与进程混用。但内核只能使用这896M物理内存(因为它的页表映射是固定的),而进程可以使用任何地方的物理内存(因为它的页表可以随意设置)。内核高128M留作其它用途,可以随意映射。内核不能直接使用的内存即“高端内存”。当内核的线性地址空间大于物理内存时,“高端”便不存在了。这种情况实际上有两种可能:一是内核线性地址空间太大,如使用64位系统;二是系统物理内存太小,如机器仅配有512M内存。两者都是{内核线性地址空间大于物理内存}的结果。
管理进程虚拟内存时,利用分页,可以把虚拟地址随意映射到任何物理地址,这才是我们印象中“分页机制的常规用法”。相反的,内核管理自己的虚拟内存时,利用分页,把“一块虚拟内存固定到一块物理内存”,反倒限制内核能使用的内存在物理内存中的位置,与我们印象中分页机制的常规作用相悖。初学者总有种“说不清道不明的不协调感”,大概就是这个原因吧。
分享到:
相关推荐
Linux内存管理编程是操作系统核心部分的关键技术之一,它涉及到如何高效地分配、使用和回收内存资源。本实验旨在帮助你深入理解Linux环境下的内存管理机制,主要包括内存映射(mapping)和解除映射(unmapping),...
安装过程中,学生需要完成多个步骤,包括创建虚拟机、设置虚拟机的名称、选择安装Linux、设置内存、创建磁盘映像文件、配置网络等。学生需要按照实验步骤,逐步完成安装过程。 在安装完成后,学生需要练习使用Linux...
文将对 Linux™ 程序员可以使用的内存管理技术进行概述,虽然关注的重点是 C 语言,但同样也适用于其他语言。文中将为您提供如何管理内存的细节,然后将进一步展示如何手工管理内存,如何使用引用计数或者内存池来半...
Linux 存储管理操作实践实验报告 ...本实验报告涵盖了 Linux 存储管理操作的基本概念和命令,通过实践和实验,学生可以更好地掌握 Linux 存储管理的基本操作和命令,并了解系统的存储情况、进程情况和内存使用情况。
Linux 操作系统实验七 Linux 存储管理操作实践 本实验报告的主要目的是指导学生学习 Linux 存储管理相关操作的基本方法,通过实验和练习,掌握 Linux 存储管理操作的基本方法和命令。 一、实验目的及要求 本实验...
对实际编程来说,理解您的内存管理器的能力与局限性至关重要。在大部分系统语言中,比如 C 和 C++,您必须进行内存管理。本文将介绍手工的、半手工的以及自动的内存管理实践的基本概念。 追溯到在 Apple II 上...
- 了解Linux内存管理的基本原理。 - 掌握虚拟内存的概念。 - **实验内容**: - 讲解物理内存与虚拟内存的区别。 - 分析Linux内存分配机制。 - 学习内存页面置换算法。 #### 实验八:设备驱动程序 - **实验...
驱动架构的核心部分,包括调度器、内存管理和设备访问等,应当是通用的,以支持尽可能多的CPU和外设。外设和IP驱动则需要跨平台,这意味着驱动核心层应致力于实现更多通用工作,以适应不同的硬件环境。 在软件栈...
在这个过程中,你将学习到操作系统的核心组件、系统调用、内存管理、进程调度、中断处理等核心概念。 首先,我们需要了解操作系统的基本架构。操作系统是计算机硬件与软件应用之间的桥梁,主要负责资源管理和任务...
4. **内存管理**:Linux 0.01版的内存管理机制相对简单,但它已经包含了基本的内存分配和释放功能。通过分析这部分代码,可以理解早期操作系统如何管理和跟踪内存使用。 5. **文件系统**:虽然早期版本的Linux支持...
Linux内核是操作系统的核心部分,它负责管理系统的硬件资源,调度进程,实现内存管理,提供文件系统和网络接口,以及安全机制等。这份压缩包包含了有关Linux内核源码的详细资源,对于想要深入理解Linux操作系统工作...
Linux内核是Linux操作系统的核心部分,负责硬件资源的管理、内存管理、进程调度等关键任务。了解Linux内核的设计与原理对于深入掌握Linux系统以及进行操作系统级别的编程和开发是至关重要的。 首先,学习Linux内核...
Linux内核是Linux操作系统的核心部分,负责管理硬件资源、提供系统调用接口、进程调度、内存管理等关键功能。0.11版虽然古老,但它包含了现代Linux内核许多基础概念的雏形。 2. **文件系统** 在Linux 0.11源码中...
7.1.4 Linux下的进程管理 7.2 Linux进程控制编程 7.3 Linux守护进程 7.3.1 守护进程概述 7.3.2 编写守护进程 7.3.3 守护进程的出错处理 7.4 实验内容 7.4.1 编写多进程程序 7.4.2 编写守护进程 7.5 本章小结 7.6 ...
3. **Linux系统调用**:介绍了如何利用C语言直接调用Linux内核提供的系统调用,如打开、读写文件、进程控制、内存管理等,这是进行系统级编程的关键。 4. **标准I/O库与文件操作**:讲解了C语言的标准输入输出库...
3. **内存管理**:包括虚拟内存、内存分配和释放机制。Vivi源码中会包含如何高效地使用和分配内存的代码。 4. **文件系统**:Linux支持多种文件系统,如EXT4、XFS和FAT。Vivi可能有自己独特的文件系统实现或对现有...
同时,了解Linux的文件系统结构(如FHS标准),熟悉shell脚本编程,以及学习如何使用包管理器(如apt、yum)安装和管理软件,都将对你的Linux技能有极大提升。 总的来说,这份"Linux_linux_"资料包提供了全面学习...
### Linux 下进程、线程与 fork 的深入理解 #### 题目背景及解析 本篇文章将基于一道经典的面试题目来探讨 Linux 下进程创建机制,特别是 `fork` 函数的工作...这一知识点对于深入理解 Linux 进程管理机制至关重要。
Linux内核是Linux操作系统的核心部分,负责管理系统的硬件资源,调度进程,实现内存管理,提供文件系统和网络接口等基本功能。对于想要从事Linux编程或者对操作系统有深入研究的人来说,了解和学习Linux内核至关重要...
随着实验的深入,学生将学习Linux的文件管理、用户与用户组管理、软件包管理,以及磁盘管理、进程管理、设备管理、内存管理等核心概念。同时,还会接触到网络配置(如TCP/IP)、网络服务配置(如NFS、Samba、DNS、...