页面回收技术案例代码分析
页面回收(Page Reclaim)是操作系统内存管理中的重要机制,主要用于在系统内存不足时回收不再使用的内存页。下面我将从Linux内核的角度分析页面回收的实现和相关代码。
Linux内核中的页面回收机制
Linux内核主要通过以下组件实现页面回收:
- kswapd:内核守护进程,负责周期性检查并维护内存平衡
- 直接回收:当分配内存失败时触发的同步回收
- LRU链表:用于跟踪最近最少使用的页面
主要数据结构
// mm/vmscan.c
struct scan_control {
unsigned long nr_to_reclaim; // 需要回收的页数
gfp_t gfp_mask; // 分配标志
/* 其他控制参数 */
int order;
int priority;
bool may_writepage;
bool may_unmap;
bool may_swap;
};
kswapd核心逻辑
// mm/vmscan.c
static int kswapd(void *p)
{
while (!kthread_should_stop()) {
if (kswapd_try_to_sleep()) { // 尝试睡眠等待唤醒
continue;
}
balance_pgdat(pgdat, order); // 执行实际的平衡工作
/* ... */
}
}
static void balance_pgdat(pg_data_t *pgdat, int order)
{
do {
sc.nr_reclaimed += shrink_zones(&sc, pgdat);
if (sc.nr_reclaimed >= sc.nr_to_reclaim)
break; // 已回收到足够的页
/* ... */
} while (--sc.priority >= 0);
}
LRU链表处理
// mm/vmscan.c
static unsigned long shrink_list(enum lru_list lru, struct scan_control *sc)
{
if (is_active_lru(lru)) {
// 处理活跃LRU链表
return shrink_active_list(nr_to_scan, lruvec, sc, lru);
} else {
// 处理非活跃LRU链表
return shrink_inactive_list(nr_to_scan, lruvec, sc, lru);
}
}
Android系统中的LMK(Low Memory Killer)
Android基于Linux内核实现了自己的低内存杀手机制:
// drivers/staging/android/lowmemorykiller.c
static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
{
for (i = 0; i < array_size; i++) {
if (other_free < lowmem_minfree[i] &&
other_file < lowmem_minfree[i]) { // 检查是否达到阈值
selected = select_bad_process(&points); // 选择得分最高的进程
if (selected) {
send_sig(SIGKILL, selected, 0); // 杀死选中的进程
rem -= selected->mm->total_vm;
}
}
}
out:
return rem;
}
static struct task_struct *select_bad_process(unsigned long *ppoints)
{
for_each_process(p) {
points = badness(p); // 计算"坏度"分数
if (points > *ppoints || !selected) {
selected = p;
*ppoints = points;
}
}
out:
return selected;
}
Windows系统的Working Set管理器
Windows使用工作集(Working Set)概念管理进程的内存使用:
// Windows内核中的工作集修剪示例逻辑(伪代码)
VOID MmTrimWorkingSet(PEPROCESS Process)
{
ULONG_PTR NumberOfPagesToTrim = CalculatePagesToTrim();
retry:
获取进程的工作集锁
遍历进程的VAD树(Virtual Address Descriptors):
对于每个符合条件的VAD区域:
调用MiTrimWorkingSetForVad修剪该区域
释放工作集锁
如果还需要更多页且可以重试:
降低修剪标准后goto retry
out:
返回结果状态;
}
Java虚拟机的垃圾收集器(GC)
虽然JVM GC不是操作系统的页面回收,但原理类似:
// HotSpot VM中CMS收集器的标记清除阶段简化逻辑(伪代码)
void CMSCollector::collect() {
初始标记(STW):
标记GC Roots直接可达的对象
并发标记:
并行标记所有可达对象
重新标记(STW):
修正并发期间变化的部分引用
并发清除:
回收不可达对象占用的空间
}
Rust语言的内存管理示例
Rust的所有权系统在编译期就确定了对象的生命周期:
fn main() {
let s1 = String::from("hello"); // s1拥有字符串
let s2 = s1; // s1的所有权转移给s2
println!("{}", s1); // 编译错误!s1不再有效
drop(s2); // s2离开作用域,内存被立即释放
}
以上展示了不同系统中页面/内存回收技术的实现思路和关键代码片段。如需更详细的某个特定系统的分析,可以进一步探讨具体部分。
内容由零声教学AI助手提供,问题来源于学员提问