从零写OS(五十三):进程退出时的资源回收

跑了一段时间之后,内核会越来越慢,最终卡死——不断创建进程、运行、退出,但内存一直在增长。原因是 proc_exit 什么都没回收。 proc_exit 原来做了什么 void proc_exit(int code) { current->exit_code = code; current->state = PROC_ZOMBIE; schedule(); // 完事了 } 进程用到的所有资源:fd、内核栈、用户页表、用户物理页——全部泄漏。 补全资源回收 void proc_exit(int code) { // 1. 关闭所有 fd for (int i = 0; i < PROC_MAX_FD; i++) { if (current->fd_table[i] >= 0) { vfs_close(current->fd_table[i]); current->fd_table[i] = -1; } } // 2. 释放内核栈 kfree(current->stack); current->stack = NULL; // 3. 释放用户页表和所有用户物理页 if (current->pml4 != kernel_pml4) { vmm_switch(kernel_pml4); // 先切回内核页表 vmm_free_user_pages(current->pml4); // 再释放 current->pml4 = NULL; } current->exit_code = code; current->state = PROC_ZOMBIE; schedule(); } vmm_free_user_pages:遍历四级页表释放 void vmm_free_user_pages(uint64_t *pml4) { for (int i4 = 0; i4 < 256; i4++) { // 只看低 256 项(用户空间) if (!(pml4[i4] & PAGE_PRESENT)) continue; uint64_t *pdpt = ENTRY_ADDR(pml4[i4]); for (int i3 = 0; i3 < 512; i3++) { // 跳过大页(内核 1GB 映射) uint64_t *pd = ENTRY_ADDR(pdpt[i3]); for (int i2 = 0; i2 < 512; i2++) { uint64_t *pt = ENTRY_ADDR(pd[i2]); for (int i1 = 0; i1 < 512; i1++) { if (pt[i1] & PAGE_USER) pmm_free(ENTRY_ADDR(pt[i1])); // 释放用户物理页 } pmm_free(pt); // 释放 PT 页 } pmm_free(pd); } pmm_free(pdpt); pml4[i4] = 0; } pmm_free(pml4); } 只遍历低 256 项对应的用户地址空间,高 256 项是内核映射(共享 kernel_pml4),不能释放。 ...

June 4, 2026 · 2 min · 大飞
京ICP备14031575号-3