趣谈Linux操作系统
刘超
网易杭州研究院云计算技术部首席架构师
立即订阅
19270 人已学习
课程目录
已完结 72 讲
0/4登录后,你可以任选4讲全文学习。
入门准备篇 (3讲)
开篇词 | 为什么要学习Linux操作系统?
免费
01 | 入学测验:你究竟对Linux操作系统了解多少?
02 | 学习路径:爬过这六个陡坡,你就能对Linux了如指掌
核心原理篇:第一部分 Linux操作系统综述 (3讲)
03 | 你可以把Linux内核当成一家软件外包公司的老板
04 | 快速上手几个Linux命令:每家公司都有自己的黑话
05 | 学会几个系统调用:咱们公司能接哪些类型的项目?
核心原理篇:第二部分 系统初始化 (4讲)
06 | x86架构:有了开放的架构,才能打造开放的营商环境
07 | 从BIOS到bootloader:创业伊始,有活儿老板自己上
08 | 内核初始化:生意做大了就得成立公司
09 | 系统调用:公司成立好了就要开始接项目
核心原理篇:第三部分 进程管理 (10讲)
10 | 进程:公司接这么多项目,如何管?
11 | 线程:如何让复杂的项目并行执行?
12 | 进程数据结构(上):项目多了就需要项目管理系统
13 | 进程数据结构(中):项目多了就需要项目管理系统
14 | 进程数据结构(下):项目多了就需要项目管理系统
15 | 调度(上):如何制定项目管理流程?
16 | 调度(中):主动调度是如何发生的?
17 | 调度(下):抢占式调度是如何发生的?
18 | 进程的创建:如何发起一个新项目?
19 | 线程的创建:如何执行一个新子项目?
核心原理篇:第四部分 内存管理 (7讲)
20 | 内存管理(上):为客户保密,规划进程内存空间布局
21 | 内存管理(下):为客户保密,项目组独享会议室封闭开发
22 | 进程空间管理:项目组还可以自行布置会议室
23 | 物理内存管理(上):会议室管理员如何分配会议室?
24 | 物理内存管理(下):会议室管理员如何分配会议室?
25 | 用户态内存映射:如何找到正确的会议室?
26 | 内核态内存映射:如何找到正确的会议室?
核心原理篇:第五部分 文件系统 (4讲)
27 | 文件系统:项目成果要归档,我们就需要档案库
28 | 硬盘文件系统:如何最合理地组织档案库的文档?
29 | 虚拟文件系统:文件多了就需要档案管理系统
30 | 文件缓存:常用文档应该放在触手可得的地方
核心原理篇:第六部分 输入输出系统 (5讲)
31 | 输入与输出:如何建立售前售后生态体系?
32 | 字符设备(上):如何建立直销模式?
33 | 字符设备(下):如何建立直销模式?
34 | 块设备(上):如何建立代理商销售模式?
35 | 块设备(下):如何建立代理商销售模式?
核心原理篇:第七部分 进程间通信 (7讲)
36 | 进程间通信:遇到大项目需要项目组之间的合作才行
37 | 信号(上):项目组A完成了,如何及时通知项目组B?
38 | 信号(下):项目组A完成了,如何及时通知项目组B?
39 | 管道:项目组A完成了,如何交接给项目组B?
40 | IPC(上):不同项目组之间抢资源,如何协调?
41 | IPC(中):不同项目组之间抢资源,如何协调?
42 | IPC(下):不同项目组之间抢资源,如何协调?
核心原理篇:第八部分 网络系统 (7讲)
43 预习 | Socket通信之网络协议基本原理
43 | Socket通信:遇上特大项目,要学会和其他公司合作
44 | Socket内核数据结构:如何成立特大项目合作部?
45 | 发送网络包(上):如何表达我们想让合作伙伴做什么?
46 | 发送网络包(下):如何表达我们想让合作伙伴做什么?
47 | 接收网络包(上):如何搞明白合作伙伴让我们做什么?
48 | 接收网络包(下):如何搞明白合作伙伴让我们做什么?
核心原理篇:第九部分 虚拟化 (7讲)
49 | 虚拟机:如何成立子公司,让公司变集团?
50 | 计算虚拟化之CPU(上):如何复用集团的人力资源?
51 | 计算虚拟化之CPU(下):如何复用集团的人力资源?
52 | 计算虚拟化之内存:如何建立独立的办公室?
53 | 存储虚拟化(上):如何建立自己保管的单独档案库?
54 | 存储虚拟化(下):如何建立自己保管的单独档案库?
55 | 网络虚拟化:如何成立独立的合作部?
核心原理篇:第十部分 容器化 (4讲)
56 | 容器:大公司为保持创新,鼓励内部创业
57 | Namespace技术:内部创业公司应该独立运营
58 | CGroup技术:内部创业公司应该独立核算成本
59 | 数据中心操作系统:上市敲钟
实战串讲篇 (9讲)
60 | 搭建操作系统实验环境(上):授人以鱼不如授人以渔
61 | 搭建操作系统实验环境(下):授人以鱼不如授人以渔
62 | 知识串讲:用一个创业故事串起操作系统原理(一)
63 | 知识串讲:用一个创业故事串起操作系统原理(二)
64 | 知识串讲:用一个创业故事串起操作系统原理(三)
65 | 知识串讲:用一个创业故事串起操作系统原理(四)
66 | 知识串讲:用一个创业故事串起操作系统原理(五)
67 | 期末测试:这些操作系统问题,你真的掌握了吗?
结束语 | 永远别轻视任何技术,也永远别轻视自己
免费
专栏加餐 (2讲)
学习攻略(一):学好操作系统,需要掌握哪些前置知识?
“趣谈Linux操作系统”食用指南
免费
趣谈Linux操作系统
登录|注册

22 | 进程空间管理:项目组还可以自行布置会议室

刘超 2019-05-17
上两节,我们讲了内存管理的三个方面,虚拟内存空间的管理、物理内存的管理以及内存映射。你现在对进程内存空间的整体布局应该有了一个大致的了解。今天我们就来详细看看第一个方面,进程的虚拟内存空间是如何管理的。
32 位系统和 64 位系统的内存布局有的地方相似,有的地方差别比较大,接下来介绍的时候,请你注意区分。好,我们现在正式开始!

用户态和内核态的划分

进程的虚拟地址空间,其实就是站在项目组的角度来看内存,所以我们就从 task_struct 出发来看。这里面有一个 struct mm_struct 结构来管理内存。
struct mm_struct *mm;
在 struct mm_struct 里面,有这样一个成员变量:
unsigned long task_size; /* size of task vm space */
我们之前讲过,整个虚拟内存空间要一分为二,一部分是用户态地址空间,一部分是内核态地址空间,那这两部分的分界线在哪里呢?这就要 task_size 来定义。
对于 32 位的系统,内核里面是这样定义 TASK_SIZE 的:
#ifdef CONFIG_X86_32
/*
* User space process size: 3GB (default).
*/
#define TASK_SIZE PAGE_OFFSET
#define TASK_SIZE_MAX TASK_SIZE
/*
config PAGE_OFFSET
hex
default 0xC0000000
depends on X86_32
*/
#else
/*
* User space process size. 47bits minus one guard page.
*/
#define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE)
#define TASK_SIZE (test_thread_flag(TIF_ADDR32) ? \
IA32_PAGE_OFFSET : TASK_SIZE_MAX)
......
当执行一个新的进程的时候,会做以下的设置:
current->mm->task_size = TASK_SIZE;
对于 32 位系统,最大能够寻址 2^32=4G,其中用户态虚拟地址空间是 3G,内核态是 1G。
对于 64 位系统,虚拟地址只使用了 48 位。就像代码里面写的一样,1 左移了 47 位,就相当于 48 位地址空间一半的位置,0x0000800000000000,然后减去一个页,就是 0x00007FFFFFFFF000,共 128T。同样,内核空间也是 128T。内核空间和用户空间之间隔着很大的空隙,以此来进行隔离。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《趣谈Linux操作系统》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(22)

  • Rainbow
    越来越看不懂了,有什么好办法吗?

    作者回复: 多看几遍哈,重点关注机制和流程

    2019-05-28
    2
    15
  • why
    - 内存管理信息在 task_struct 的 mm_struct 中
    - task_size 指定用户态虚拟地址大小
        - 32 位系统:3G 用户态, 1G 内核态
        - 64 位系统(只利用 48 bit 地址): 128T 用户态; 128T 内核态
    - 用户态地址空间布局和管理
        - mm_struct 中有映射页的统计信息(总页数, 锁定页数, 数据/代码/栈映射页数等)以及各区域地址
        - 有 vm_area_struct 描述各个区域(代码/数据/栈等)的属性(包含起始/终止地址, 可做的操作等), 通过链表和红黑树管理
        - 在 load_elf_bianry 时做 vm_area_struct 与各区域的映射, 并将 elf 映射到内存, 将依赖 so 添加到内存映射
        - 在函数调用时会修改栈顶指针; malloc 分配内存时会修改对应的区域信息(调用 brk 堆; 或调用 mmap 内存映射)
        - brk 判断是否需要分配新页, 并做对应操作; 需要分配新页时需要判断能否与其他 vm_area_struct 合并
    - 内核地址空间布局和管理
        - 所有进程看到的内核虚拟地址空间是同一个
        - 32 位系统, 前 896MB 为直接映射区(虚拟地址 - 3G = 物理地址)
            - 直接映射区也需要建立页表, 通过虚拟地址访问(除了内存管理模块)
            - 直接映射区组成: 1MB 启动时占用; 然后是内核代码/全局变量/BSS等,即 内核 ELF文件内容; 进程 task_struct 即内核栈也在其中
            - 896MB 也称为高端内存(指物理内存)
            - 剩余虚拟空间组成: 8MB 空余; 内核动态映射空间(动态分配内存, 映射放在内核页表中); 持久内存映射(储存物理页信息); 固定内存映射; 临时内存映射(例如为进程映射文件时使用)
        - 64 位系统: 8T 空余; 64T 直接映射区域; 32T(动态映射); 1T(物理页描述结构 struct page); 512MB(内核代码, 也采用直接映射)
    2019-05-22
    9
  • 有铭
    老师,之前你说过,内核态对于所有进程都是相同的,那时我就问过,这话的意思是不是说内核态内存在真实的物理内存里其实只有1份?

    作者回复: 是的,内核对于所有的进程,不但物理内存只有一份,虚拟内存也是只有一份。也就是说A进程用户态访问x虚拟地址和B进程用户态访问x虚拟地址是不同的虚拟地址,也即A进程用户态在x虚拟地址里面放了一个数值w,B进程用户态的x虚拟地址看不到w,对应的也是不同的物理地址。A进程内核态访问的y虚拟地址,和B进程内核态访问的y虚拟地址,是通一个虚拟地址,也对应相同的物理地址。也即A进程内核态在y虚拟地址方一个数值n,B进程的内核态如果能够访问y虚拟地址的话,也能看到n

    2019-05-17
    6
  • Geek_49fbe5
    老师,如果一台X86的物理机的内存只有1G,那是不是意味着这台机子装不了linux操作系统呢,因为内核就得用1G的内存?

    作者回复: 要区分虚拟地址空间和物理地址空间,可以虚拟的大,物理的小

    2019-06-01
    1
    4
  • G.S.K
    老师好,vm_area_struct描述内存区域,内存区域有text,data,bss,堆,mmap映射,栈区域,一个进程的vm_area_struct个数只有这6个吗?

    作者回复: 不是的,堆就不一定连续

    2019-06-12
    3
  • 小松松
    请问下,像slab、伙伴系统这些工具跟用户空间和内核空间的虚拟内存、物理内存有什么关系呢? 一直很迷惑,请老师解答下。

    作者回复: 伙伴系统是物理内存的分配,slub是划分为更小,但是都要变成虚拟地址才能被访问。

    2019-05-20
    2
  • tuyu
    看到这里, 我觉得我们不能太关注code问题, 应该多关注数据结构和数据结构的关系, 这样就有目标了

    作者回复: 是的,重点关注数据结构和流程,代码作为参考

    2019-08-14
    1
  • 🍀吴昊
    我请问下最后两张图没有看明白
    1 32位直接映射区为什么还保存了堆信息?不是存在vmalloc来直接分配内存的嘛?
    2 64位512M 用于存放内核代码段、全局变量、BSS 等。为什么图中却只映射到代码,而是由直接映射区去映射?

    作者回复: 可能是图有些误解,堆在High memory区域。图中指的是数据结构都保存在直接映射区。但是vmalloc分配出来是给内核用的。

    内核代码,全局变量,bss都是在代码段的。其他动态生成的变量都是在直接映射区的

    2019-06-14
    1
  • 一笔一画
    老师,请教下,64位布局里面,为什么会有这个8T空档?另外,32位上用户进程是优先使用高端内存吗?

    作者回复: 设计的时候就预留的呀。如果分配堆有高端内存是会优先使用的

    2019-05-17
    1
  • 追风筝的人
    看不懂了
    2019-11-23
  • loser
    老师,程序运行中的变量值。是怎么被虚拟内存管理的?比如 int a=1。它是怎么知道写入到哪一个物理地址的
    2019-11-08
  • 柳长青
    老师,可不可以这样理解:即用户的虚拟内存和内核的虚拟内存在物理内存上并不是连续的,所以它们都可以在直接映射区(前896M)进行操作。
    2019-11-03
  • 耀明
    那两个图看不太懂,跟文字描述的有很大的不同。
    2019-10-22
  • kdb_reboot
    最后总结中的mmap和堆直接指到了物理内存,没看懂是什么意思,老师能解释一下吗?
    2019-10-02
    1
  • 张智凯
    请问 系统调用brk里用这样一段 if (do_brk(oldbrk, newbrk-oldbrk, &uf) < 0) ; goto out,如果do_brk返回小于0的值是分配堆内存失败了吗?do_brk会返回do_brk_flags的返回值,但是看do_brk_flags这个函数里只会返回0啊,是do_brk_flags没写全吗
    2019-09-13
  • haozhang
    内核栈在哪呢?

    作者回复: 内核的虚拟地址空间

    2019-08-20
  • 饭粒
    老师,我想问下文中描述的是虚拟内存的布局,即使物理地址比较小,比如32位系统小于4g,于进程而言使用的还是4g的虚拟地址?但现在如果物理内存小于896M,这样物理内存大小小于内核态中直接一对一映射区域的大小,这种linux怎么处理?

    作者回复: 内存的分配就在直接映射区了。

    2019-06-29
    1
  • 幸运的🐴
    刘老师,为什么内核在load用户空间的内存映射到物理页的时候要自己在内核的持久映射区也建议一个映射呢,不能使用用户空间的映射吗?这样的话,持久映射区会不会有空间不够的情况?因为这块的虚拟空间很小(<1G),如果我mmap一个很大的文件到用户空间,那很明显没办法把这个文件映射到内核的虚拟空间来呀,这块它是怎么做的呢?另外,这个过程跟load elf不是类似的么?对于用户空间的进程的代码区,数据区等,还是需要把磁盘上的页读进内存吧?这个过程也需要在内核先映射,读完之后再解除映射?

    作者回复: 在内核里面,得使用虚拟地址将内容读取到内存来。读一部分,映射一部分。load_elf_binary会最终调用do_mmap_pgoff,一样的

    2019-06-16
  • 烈日融雪
    请问 __randomize_layout 是让struct 结构变量在编译时候 里面熟悉不按默认的定义顺序存储么?

    作者回复: 在编译的时候,结构体的数据存放不会按照声明顺序,而是根据函数名以及随机种子,打乱存储顺序。

    2019-05-23
  • 小美
    内核自身启动的内核进程是如何布局内存的?

    作者回复: 一开始讲过前1m的,后面的内存管理那一节讲

    2019-05-23
收起评论
22
返回
顶部