目录
在页面置换过程中,可能会出现一种最糟糕的情况,即刚刚换出的页面马上又要换入内存,刚刚换入的页面马上又要换出。这种频繁的页面调度行为称为 "抖动" 或 "颠簸"。当一个进程在换页上所花费的时间多于执行时间时,该进程就处于 "抖动" 状态。
"抖动" 的产生原因
"抖动"(Thrashing)是计算机系统中一种性能严重下降的现象,其主要原因是系统中同时运行的进程过多,导致分配给每个进程的物理块数不足,无法满足进程正常运行的基本要求。
"抖动" 产生的详细原因
-
进程过多,物理块不足:
- 内存分配:当系统中运行的进程数量增加时,可用的物理内存块(页框)分配给每个进程的数量会减少。
- 工作集不足:每个进程需要一定数量的页框(工作集)来保持高效运行。如果分配的页框数量不足,进程将在运行过程中频繁缺页。
-
频繁缺页中断:
- 缺页中断:由于物理块不足,进程在访问所需页面时,频繁发生缺页中断,需请求操作系统将所需的页从磁盘调入内存。
- 页面换入/换出:频繁的缺页中断导致页面频繁换入/换出,进一步增加了磁盘I/O操作的负担。
-
磁盘I/O负载增加:
- 排队等待:系统中排队等待页面调入/调出的进程数量增加,磁盘I/O操作频繁,导致磁盘访问时间增加。
- I/O瓶颈:磁盘I/O成为系统瓶颈,频繁的磁盘读写操作显著降低了系统的整体响应速度。
-
处理器利用率下降:
- 等待状态:由于频繁的缺页中断,进程大部分时间都处于等待页面调入/调出的状态,实际执行有效工作的时间减少。
- 低利用率:处理器的利用率急剧下降,因为它们总是在等待磁盘I/O操作完成,没有充足的内存数据来处理。
"抖动" 的示例场景
假设一个系统中有多个进程同时运行,而系统的物理内存不足以容纳所有进程的工作集。每个进程都需要频繁访问不同的页面,导致频繁的页面换入/换出。
示例伪代码:
while (runningProcesses > memory.availablePageFrames) {
for each process in runningProcesses {
if (process.pageFault()) {
pageToReplace = selectVictimPage();
evictPage(pageToReplace);
loadPage(process.requiredPage());
}
}
}
在这种情况下,系统不断进行页面置换,磁盘I/O操作频繁,导致"抖动"现象的产生。
解决"抖动" 的方法
-
调整多道程度:
- 减少并发进程数量:通过减少同时运行的进程数量,确保每个进程能分配到足够的页框,减少缺页中断的频率。
- 进程优先级调整:根据进程的重要性和内存需求调整其优先级,优先保证关键进程的内存需求。
-
工作集模型:
- 工作集管理:操作系统动态监测和调整每个进程的工作集大小,确保进程在运行时能够保持较高的内存利用率。
- 页面置换算法改进:采用更智能的页面置换算法,如LRU(最近最少使用)、LFU(最少使用)等,减少频繁置换的发生。
-
虚拟内存优化:
- 虚拟内存扩展:通过增加虚拟内存(如交换分区或交换文件)来缓解物理内存不足的问题。
- 预读和预写技术:提前将可能需要的页面加载到内存中,减少缺页中断的发生。
-
系统资源监控:
- 实时监控:通过实时监控系统资源使用情况,及时发现并解决"抖动"问题。
- 自动调优:系统自动调整内存分配策略和进程调度策略,优化资源利用。
缺页率与物理块数的关系
1. 缺页率与内存大小的关系
缺页率是指在一定时间内发生缺页中断的频率。当一个进程频繁访问的页面数目高于可用的物理页框数目时,缺页中断的频率会增加,从而导致所谓的“抖动”现象。抖动是指系统频繁发生缺页中断,导致处理机的大部分时间被用于页面调入调出操作,而非实际执行进程的指令。以下是缺页率与物理块数关系的详细分析:
2. 虚拟内存技术
虚拟内存技术允许系统在物理内存无法容纳所有进程的情况下,仍能保留更多的进程以提高系统效率。在稳定状态下,主存的几乎所有空间都被进程块占据,从而使处理机和操作系统可以直接访问尽可能多的进程。然而,如果管理不当,频繁的页面调入调出操作会大大降低系统效率。
3. 缺页率与物理块数关系的分析
-
物理块数少时:
- 当物理块(物理页框)数目较少时,可存放的页面数目有限。如果一个进程所需的页面数目超过了物理块数目,则会频繁发生缺页中断。
- 这时系统会陷入频繁的页面调度操作中,每次都需要将不在内存中的页面从磁盘调入,导致高缺页率。
-
物理块数增加:
- 随着物理块数的增加,能够同时驻留在内存中的页面数目也增加,从而减少了缺页中断的发生。
- 缺页率会逐渐下降,系统的性能会有所提升。
-
记忆效应:
- 根据局部性原理,进程在一段时间内倾向于重复访问一组相对较小的页面集合。因此,当可用物理块数足够大以容纳这些局部性页面时,缺页率会显著降低。
- 超过这一临界点后,进一步增加物理块数对降低缺页率的效果会逐渐减小。
-
抖动现象:
- 如果某个进程频繁访问的页面数远高于物理块数,系统将会频繁发生缺页中断。这种情况下,大部分时间会花在页面调入调出操作上,而不是执行进程的指令,导致系统效率大幅下降。
4. 示例图解
可以通过一个示意图来展示缺页率与物理块数之间的关系:
缺页率
|
| /--------------------
| / |
| / |
| / |
| / |
| / |
| / |
| / |
| / |
| / |
| / |
|/ |
|-------------------------
物理块数
在示意图中,缺页率随着物理块数的增加而下降,但在达到某个临界点后,再增加物理块数对缺页率的影响趋于平缓。
5. 管理策略
为了避免抖动现象,系统可以采用以下策略:
-
工作集模型:
- 维护每个进程的“工作集”,即在一段时间内被频繁访问的页面集合。确保工作集能完全驻留在物理内存中,以降低缺页率。
-
页面置换算法优化:
- 使用更高效的页面置换算法,如LRU(最近最少使用)或改进的Clock算法,以更智能地决定哪些页面可以被换出,从而减少不必要的缺页中断。
-
内存分配策略:
- 根据进程的需求动态分配内存,确保高优先级或关键进程有足够的物理内存资源,从而减少关键进程的缺页中断频率。
工作集(驻留集)
工作集(或驻留集)是一个进程在某段时间间隔内需要访问的页面集合。工作集概念的引入旨在识别和保留经常被访问的页面,从而提升系统性能,减少缺页中断次数。长期不被使用的页面则从工作集中丢弃。
工作集模型的原理
工作集模型的原理主要包括以下几个方面:
-
跟踪进程的工作集:
- 操作系统持续跟踪每个进程的页面访问情况,以识别其工作集。工作集的大小是动态变化的,取决于进程在一定时间间隔内访问的页面数量。
- 工作集通常使用时间窗口(或滑动窗口)来确定,比如在过去的Δ时间内访问的所有页面构成当前的工作集。
-
分配物理块:
- 系统为每个进程分配物理内存块,使其大小大于进程的工作集。这确保了经常被访问的页面都能驻留在内存中,从而减少缺页中断。
- 如果进程的工作集增大,系统需要为其分配更多的物理块;如果工作集减小,系统可以回收部分物理块。
-
增加并发度:
- 当还有空闲物理块时,系统可以调入更多的进程以增加系统的并发度和资源利用率。更多的进程在内存中运行可以提升系统的响应速度和效率。
-
防止 "抖动" 现象:
- "抖动" 现象指的是频繁的页换入换出,导致系统性能急剧下降。为了防止这种现象,当所有进程的工作集之和超过了可用物理块的总数时,操作系统会采取措施。
- 操作系统会暂停一个或多个进程,将其页面调出内存,并将回收的物理块分配给其他活跃进程。这种策略可以有效减少抖动,确保系统维持稳定的性能。
示例
假设系统中有三个进程A、B、C,每个进程的工作集和物理块需求如下:
- 进程A的工作集需要3个物理块。
- 进程B的工作集需要4个物理块。
- 进程C的工作集需要2个物理块。
- 系统共10个物理块。
场景一:没有抖动
- 进程A、B、C的工作集分别为3、4、2,总需求为9个物理块。
- 系统分配:
- 进程A:3个块
- 进程B:4个块
- 进程C:2个块
- 还有1个空闲块,可以用于增加新的进程或应对突发需求。
场景二:抖动防御
- 假设进程D加入,需要3个物理块,但系统已有9个块被占用。
- 总需求为3+4+2+3=12个块,超过系统总数。
- 操作系统决定暂停进程C并将其2个块分配给进程D。
- 新分配:
- 进程A:3个块
- 进程B:4个块
- 进程D:3个块
通过暂停短暂不需要高频访问的进程(如C),系统有效防止了抖动现象。
正确选择工作集大小
1. 工作集概念
工作集(Working Set)是指在特定时间间隔内,一个进程频繁访问的页面集合。正确选择工作集大小对于优化存储器利用率和提高系统吞吐量至关重要。工作集的大小取决于进程的局部性原理,即时间局部性和空间局部性。
2. 局部性原理
-
时间局部性:
- 时间局部性指的是某个时间段内被访问过的页面在短时间内可能会再次被访问。例如,循环语句中的代码和数据通常具有较高的时间局部性。
-
空间局部性:
- 空间局部性指的是如果一个页面被访问,那么它附近的页面也很可能会被访问。例如,数组遍历和相邻的内存分配通常具有较高的空间局部性。
3. 分析访问模式
通过分析进程的访问模式,可以估计出最适合该进程的工作集大小。具体方法如下:
-
监控页面访问频率:
- 记录进程在一段时间内的页面访问情况,统计每个页面的访问频率和时间间隔。
-
时间窗口法:
- 使用固定长度的时间窗口来观察进程的页面访问行为。时间窗口可以滑动,逐步统计每个时间窗口内的页面集合,从而确定工作集大小。
-
页面故障频率法:
- 监控进程的页面故障频率。如果页面故障频率较高,则说明当前工作集不足,需要增加工作集大小;反之,如果页面故障频率较低,则可以考虑减少工作集大小。
4. 动态调整工作集大小
为了有效地利用内存资源,可以采用动态调整工作集大小的策略:
-
自适应策略:
- 根据进程的实际需求动态调整工作集大小。系统可以在运行时监控每个进程的页面访问行为,实时调整工作集大小以适应变化的访问模式。
-
优先级策略:
- 为高优先级进程分配更多的内存资源,确保它们的工作集能够完全驻留在物理内存中,从而减少页面故障,提高系统吞吐量。
-
阈值策略:
- 设置页面故障频率的上下限阈值,当页面故障频率超过上限时,增大工作集;当页面故障频率低于下限时,减小工作集。
5. 示例图解
可以通过一个示意图来展示工作集大小与页面故障频率之间的关系:
页面故障频率
|
| /-----------
| / |
| / |
| / |
| / |
| / |
| / |
| / |
| / |
| / |
| / |
| / |
|/ |
|-------------------------
工作集大小
在示意图中,页面故障频率随着工作集大小的增加而下降,但在达到某个临界点后,进一步增加工作集大小对降低页面故障频率的效果会逐渐减小。
6. 实现示例
以下是一个简单的Python代码示例,演示如何动态调整工作集大小:
class WorkingSetManager:
def __init__(self, initial_size):
self.working_set_size = initial_size
self.page_faults = 0
self.time_window = 10
self.access_records = []
def access_page(self, page_number):
if page_number not in self.access_records:
self.page_faults += 1
if len(self.access_records) >= self.working_set_size:
self.access_records.pop(0) # 移除最旧的页面
self.access_records.append(page_number)
def adjust_working_set(self):
if self.page_faults > self.time_window * 0.5: # 页面故障频率高
self.working_set_size += 1
elif self.page_faults < self.time_window * 0.1: # 页面故障频率低
self.working_set_size = max(1, self.working_set_size - 1)
self.page_faults = 0 # 重置页面故障计数器
# 示例页面访问序列和初始工作集大小
pages = [7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2]
manager = WorkingSetManager(initial_size=3)
for i, page in enumerate(pages):
manager.access_page(page)
if (i + 1) % manager.time_window == 0:
manager.adjust_working_set()
print(f"Working set size: {manager.working_set_size}, Access records: {manager.access_records}")
print(f"Final working set size: {manager.working_set_size}")
结语
"抖动" 是页面置换过程中最糟糕的情况,导致处理机的利用率急剧下降。工作集模型为防止 "抖动" 提供了解决方案,通过跟踪进程的工作集,并为进程分配大于其工作集的物理块,系统可以有效地管理内存,防止出现 "抖动"。正确选择工作集大小,对提高存储器利用率和系统吞吐量至关重要。了解 "抖动" 与工作集的关系,有助于我们优化内存管理,提高系统的性能和稳定性。