1. “共享段”的实现 与 “共享段表”的辨析
在分段式存储管理中,确实存在“共享段” (Shared Segment) 的概念,这也是分段管理相对于分页管理的一个主要优点。
共享段的作用与实现原理:
分段管理的地址空间是二维的、非连续的、按逻辑意义划分的。每个段(如主程序段、子程序段、数据段、堆栈段)都有其独立的逻辑含义。这使得“共享”变得非常自然和方便。
-
作用: 主要用于共享代码(如C标准库、动态链接库)或共享数据。这极大地节省了内存,因为同一份库代码或数据只需在物理内存中存放一份,就可以被多个进程使用。
-
实现方式:
-
每个进程都有自己独立、私有的段表。这个段表是进程上下文的一部分,归进程自己所有。
-
当需要共享某个段(例如,一个共享库的代码段)时,系统会在不同进程的各自段表中,创建一个指向同一物理内存区域的表项。
-
这个表项包含了该共享段的物理基地址和段长。在不同进程的段表中,这个基地址和段长是完全相同的。
-
但是,该共享段在不同进程的逻辑地址空间中,可以有不同的段号。
-
图示理解:
假设进程P1和P2共享一个代码段(如libc.so)。
进程P1的逻辑地址空间 进程P2的逻辑地址空间
+-------------------------+ +-------------------------+
| 段0 (主程序) | | 段0 (主程序) |
+-------------------------+ +-------------------------+
| 段1 (数据) | | 段1 (数据) |
+-------------------------+ +-------------------------+
| 段2 (共享库, 段号为2) | | ... |
+-------------------------+ | |
| ... | | 段5 (共享库, 段号为5) |
+-------------------------+ +-------------------------+
| |
V V
P1的段表 (私有) P2的段表 (私有)
+-----+------+------+ +-----+------+------+
| 段号| 基址 | 段长 | | 段号| 基址 | 段长 |
+-----+------+------+ +-----+------+------+
| 0 | 2000 | 100K | | 0 | 8000 | 150K |
+-----+------+------+ +-----+------+------+
| 1 | 4000 | 50K | | 1 | 12000| 80K |
+-----+------+------+ +-----+------+------+
| 2 | 5000 | 200K |------\ /----| 5 | 5000 | 200K |
+-----+------+------+ \ / +-----+------+------+
| ... | ... | ... | \ / | ... | ... | ... |
+-----+------+------+ \/ +-----+------+------+
/ \
/ \
/ \
物理内存
+------------------------------------+
| ... |
+------------------------------------+
| 地址5000: 共享库代码段 (200K) |
+------------------------------------+
| ... |
+------------------------------------+
正确的说法是,通过在各自私有的段表中设置指向同一物理段的表项来实现段的共享。
2. 为什么没有“共享页表”?
基于上面的讨论,我们来分析为什么不能用同样的方式共享“页表”。
核心原因: 分页管理的地址空间是一维、线性的,页表的作用是映射整个连续的逻辑地址空间。
-
地址空间的整体性:
-
一个进程的页表,必须负责映射它从0到最大虚拟地址的整个、连续的、巨大的逻辑地址空间。页表的结构和内容与这个进程的整体内存布局紧密绑定。
-
如果两个进程 P1 和 P2 共享同一个页表,那就意味着它们的虚拟地址到物理地址的映射关系是完全一样的。这使得 P1 和 P2 成了完全相同的进程映像,它们不再是两个独立的进程,而更像是同一个进程的两个执行线程(实际上,线程共享地址空间正是通过共享页表等映射信息实现的)。这违背了我们让两个独立进程共享部分内存的初衷。
-
-
缺乏逻辑独立性:
-
页面是物理划分的单位(例如4KB),它本身没有独立的逻辑含义。我们想共享的通常是一个逻辑实体,比如一个函数库、一个数据结构。这个逻辑实体可能跨越多个页面。
-
在分段中,共享一个“段”非常清晰。但在分页中,我们无法说“共享第10号页表”,因为页表本身是与整个进程地址空间绑定的。
-
3. 分页系统中如何实现内存共享?
那么,分页系统就不能共享内存了吗?当然可以,只是实现方式不同。
分页系统共享内存的方式:
与分段系统类似,分页系统实现共享也是通过让不同进程的私有页表,将某些逻辑页面映射到相同的物理页帧上来实现的。
-
实现方式:
-
每个进程拥有自己独立、私有的页表。
-
当需要共享一块内存时(例如,一个12KB的共享库,占3个页面),系统会将这块内存在物理上分配3个连续或不连续的页帧。
-
然后,在需要共享这块内存的所有进程的各自页表中,找到对应的逻辑页面(例如P1的10、11、12号页,P2的20、21、22号页),并将这些页表项的内容设置为指向相同的物理页帧号。
-
图示理解:
P1的页表 (私有) P2的页表 (私有)
+-----+------+ +-----+------+
|页号 | 帧号 | |页号 | 帧号 |
+-----+------+ +-----+------+
| ... | ... | | ... | ... |
+-----+------+ +-----+------+
| 10 | 7 |--------\ /--| 20 | 7 |
+-----+------+ \ / +-----+------+
| 11 | 8 |----------\ /----| 21 | 8 |
+-----+------+ \ / +-----+------+
| 12 | 9 |------------\ /------| 22 | 9 |
+-----+------+ \ / +-----+------+
| ... | ... | \ / | ... | ... |
+-----+------+ \ / +-----+------+
V
物理内存
+------------------------------------+
| ... |
+------------------------------------+
| 物理帧7 (共享内存第1部分) |
+------------------------------------+
| 物理帧8 (共享内存第2部分) |
+------------------------------------+
| 物理帧9 (共享内存第3部分) |
+------------------------------------+
| ... |
+------------------------------------+
总结
特性 | 分段式 (Segmentation) | 分页式 (Paging) |
---|---|---|
基本单位 | 段 (Segment):逻辑单位,长度可变 | 页 (Page):物理单位,大小固定 |
地址空间结构 | 二维、分立的段集合 | 一维、线性的连续空间 |
"表"的归属 | 每个进程有私有的段表 | 每个进程有私有的页表 |
共享实现方式 | 在不同进程的私有段表中,创建指向同一物理段的表项。共享以整个段为单位,非常方便。 | 在不同进程的私有页表中,创建指向相同物理页帧的页表项。共享以页为单位,管理相对复杂。 |
为何没有"共享表" | 因为段表是私有的。共享的是表项指向的内容。 | 因为页表映射的是整个线性地址空间,共享整个页表意味着两个进程完全相同,失去了独立性。 |