繁体   English   中英

进程如何共享虚拟内存 (Linux)

[英]How processes share virtual mem (Linux)

我不确定我的问题是 Linux 问题还是与操作系统无关的问题。

如果我运行了三个进程(我们称它们为 P0、P1 和 P2),并且它们在用户看来是同时运行的,那么它们如何共享?

他们每个人都用户空间维护自己的堆栈、堆等吗?

情景A

或者他们只是拥有整个堆栈、堆等,直到下一个进程出现并抢占它?

情景B

在 Linux 和大多数其他当前使用的通用操作系统中,内存根本不是单个线性阵列:底层物理内存使用虚拟内存页面级别进行管理。

本质上,每个进程都有自己的虚拟地址空间。 其中大部分是空的、未映射的——尝试访问它会导致分段错误或一般保护违规,通常会杀死进程——; 进程只能访问内核明确设置为进程可以访问的内存。

在大多数情况下,进程也不能直接访问内核内存。 为了执行系统调用——例如,打开或读取或写入文件或设备——,处理器核心本质上将上下文切换到内核​​模式,内核数据结构和当前进程使用的内存在用户空间可以同时访问(但不一定在内核空间中与用户空间中的虚拟地址相同)。

这意味着现在每个进程可访问的内存实际上非常分散和不连续:

    ╔════════╗   ╔════════╗   ╔═══════╗
    ║  Code  ║   ║  Data  ║   ║ Stack ║
    ╚════════╝   ╟────────╢   ╚═══════╝
    ╔════════╗   ║  BSS   ║
    ║ ROdata ║   ╟────────╢
    ╚════════╝   ║  Heap  ║
    ╔════════╗   ╚════════╝
    ║  Libs  ║
    ╚════════╝

如果使用地址空间随机化,则上述每个段的地址甚至从一次运行到下一次运行都可能有所不同。 通常,代码(只读且可执行)和只读数据加载到固定地址,但动态链接库、堆栈和数据的地址各不相同。

也没有理由为什么上面的一个地址应该比另一个高或低,所以我特意把它们放在一起,而不是在一个列中!

初始化数据和未初始化数据通常在一个连续的段中,只有初始化数据部分从可执行文件(数据段)加载。 在 Unix 和 POSIX-like 系统中,堆跟随未初始化的数据(并且可以使用brk()sbrk()系统调用进行扩展)。 在像 Linux 这样的 POSIXy 系统中,实际上大多数其他系统中,进程也可以通过(匿名)内存映射拥有额外的“堆”。

进程中的初始线程也获得了一个单独的堆栈段。 任何额外的线程也将获得自己的堆栈。

(学习使用POSIX线程的一个典型练习是找出一个进程可以创建多少个并发线程。Linux中典型的结果只有一百或几百个,很多学习者觉得这很奇怪。造成这种情况的原因较低的数字实际上是默认的堆栈大小,在当前的 GNU/Linux 桌面发行版中大约为 8 兆字节;仅一百个线程的堆栈就需要近 1 GB 的内存,因此并发线程的数量主要受内存限制可用于他们的堆栈。一个非递归线程工作函数最多只需要几十千字节的堆栈,并且只需要几行代码就可以为新创建的pthread显式设置堆栈大小。然后,最大并发数单个进程中的线程数通常为一千或更多,通常取决于系统管理员设置的进程限制或默认情况下的分布。)

正如您在上图中所看到的,没有“操作系统”。

事实上,我们确实需要将“操作系统”分成两个完全独立的部分:内核(提供在系统调用中实现的功能)和库(实现用户空间处理器可用的非系统调用接口,通常从标准 C 库开始)。

我只在上面画了一个“Libs”(用于库)框,但在实践中,每个库的代码往往会获得自己单独的内存段。

让我们看一下 Linux 中的一个特定示例(因为这就是我现在正在使用的); cat命令。 在 Linux 中, /sys/proc文件系统是特殊的伪文件系统树,它们根本不对应任何存储介质上的任何文件,而是在访问它们时由内核构建——本质上,它们是内核提供的内核已知数据的实时视图。 /proc/self子树包含有关“当前进程”的信息——也就是说,在检查该目录的任何进程上。 (如果不止一个人同时检查它,他们每个人只能看到自己的数据,因为这不是一个普通的文件系统,而是内核创建的,并根据需要提供。)

/proc/self/maps (或/proc/PID/maps用于进程 ID 为PID的进程)伪文件描述进程具有的所有内存映射。 如果我们运行cat /proc/self/maps ,我们可以看到cat进程本身的映射。 在我的机器上(在 x86-64 架构上运行的 64 位 Linux)它显示

00400000-0040c000 r-xp 00000000 08:05 2359392             /bin/cat
0060b000-0060c000 r--p 0000b000 08:05 2359392             /bin/cat
0060c000-0060d000 rw-p 0000c000 08:05 2359392             /bin/cat
0215f000-02180000 rw-p 00000000 00:00 0                   [heap]
7f735b70f000-7f735c237000 r--p 00000000 08:05 658950      /usr/lib/locale/locale-archive
7f735c237000-7f735c3f6000 r-xp 00000000 08:05 1179825     /lib/x86_64-linux-gnu/libc-2.23.so
7f735c3f6000-7f735c5f6000 ---p 001bf000 08:05 1179825     /lib/x86_64-linux-gnu/libc-2.23.so
7f735c5f6000-7f735c5fa000 r--p 001bf000 08:05 1179825     /lib/x86_64-linux-gnu/libc-2.23.so
7f735c5fa000-7f735c5fc000 rw-p 001c3000 08:05 1179825     /lib/x86_64-linux-gnu/libc-2.23.so
7f735c5fc000-7f735c600000 rw-p 00000000 00:00 0 
7f735c600000-7f735c626000 r-xp 00000000 08:05 1179826     /lib/x86_64-linux-gnu/ld-2.23.so
7f735c7fe000-7f735c823000 rw-p 00000000 00:00 0 
7f735c823000-7f735c825000 rw-p 00000000 00:00 0 
7f735c825000-7f735c826000 r--p 00025000 08:05 1179826     /lib/x86_64-linux-gnu/ld-2.23.so
7f735c826000-7f735c827000 rw-p 00026000 08:05 1179826     /lib/x86_64-linux-gnu/ld-2.23.so
7f735c827000-7f735c828000 rw-p 00000000 00:00 0 
7ffeea455000-7ffeea476000 rw-p 00000000 00:00 0           [stack]
7ffeea48b000-7ffeea48d000 r--p 00000000 00:00 0           [vvar]
7ffeea48d000-7ffeea48f000 r-xp 00000000 00:00 0           [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0   [vsyscall]

前三个是进程本身的代码 ( r-xp )、只读数据 ( r--p ) 和初始化数据 ( rw-p )。 进程可以使用sbrk()扩展的数据段(或“堆”)是第三个(即, sbrk(0)将返回0x60d000 。)

该进程有一些堆,正确的,从地址 0x215f000 到(但不包括)0x2180000。

下一段是当前语言环境数据的只读映射。 C 库将此用于语言环境感知接口。

接下来的四个部分是 C 库本身:代码 ( r-xp )、C 库以某种方式使用/需要的通常无法访问的映射 ( ---p )、只读数据 ( r--p ) 和初始化数据( rw-p )。

下一个段和最后一列中没有名称的其他段,具有保护模式 ( rw-p ) 是单独的数据段或堆。

接下来的三段是 Linux 中使用的动态链接器, ld.so 同样,有一个代码段 ( r-xp )、只读数据段 ( r--p ) 和初始化数据段 ( rw-p )。

[stack]段是初始线程的堆栈。 cat是单线程的,所以它只有一个线程。) [vvar]段由内核提供(允许进程直接访问某些内核提供的数据,而不必承担系统调用的开销)。 [vdso][vsyscall]段由内核提供,用于加速不需要完整上下文切换即可完成的系统调用。

因此,正如您所看到的,与旧的 C 和操作系统书籍相比,完整的图片更加零散,但也更自由(如更自由的形式)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM