适合女生做的网站主题,成都专业网站建设机构,wordpress 代码样式,微信公众号登录入口下载首先#xff0c;内存管理结构在操作系统中通常指的是用于管理进程内存的数据结构。在Linux中#xff0c;每个进程都有一个mm_struct#xff08;内存描述符#xff09;#xff0c;它包含了进程内存空间的所有信息。这应该是用户最想了解的核心概念。
这里需要解释清楚结构在…首先内存管理结构在操作系统中通常指的是用于管理进程内存的数据结构。在Linux中每个进程都有一个mm_struct内存描述符它包含了进程内存空间的所有信息。这应该是用户最想了解的核心概念。这里需要解释清楚结构在fork()和exec()中是如何被操作和变化的。比如在fork()时mm_struct如何被复制写时复制而在exec()时它又如何被全新的内存映射替换。另外虚拟内存的具体组织方式也要解释清楚比如区域划分代码段、数据段、堆、栈等以及内核如何通过页表管理这些区域。可以提及vm_area_structVMA结构它描述了进程地址空间中的一个连续区域。最后为了帮助理解提供一个简单的类比并将这些结构与实际观察命令如/proc/pid/maps联系起来这样就能将理论知识与实际系统行为对应起来。内存管理结构进程地址空间的核心骨架内存管理结构是操作系统内核用来描述和管理进程虚拟地址空间的数据结构。它定义了进程能看到的内存地图记录哪些区域可用、哪些已分配、以及各自的权限和属性。一、核心结构mm_structLinux中的内存描述符基本定义// 简化版的mm_struct实际内核代码更复杂structmm_struct{// 1. 内存区域管理structvm_area_struct*mmap;// 虚拟内存区域链表structrb_rootmm_rb;// 虚拟内存区域红黑树用于快速查找// 2. 内存统计unsignedlongtotal_vm;// 映射的总页面数unsignedlonglocked_vm;// 被锁定的页面数unsignedlongpinned_vm;// 被钉住的页面数不可换出unsignedlongdata_vm;// 数据段页面数unsignedlongexec_vm;// 代码段页面数unsignedlongstack_vm;// 栈页面数// 3. 地址空间布局unsignedlongstart_code,end_code;// 代码段起始和结束unsignedlongstart_data,end_data;// 数据段起始和结束unsignedlongstart_brk,brk;// 堆的起始和当前brkunsignedlongstart_stack;// 栈起始地址unsignedlongarg_start,arg_end;// 命令行参数区域unsignedlongenv_start,env_end;// 环境变量区域// 4. 页表管理pgd_t*pgd;// 页全局目录指向第一级页表atomic_tmm_users;// 使用该地址空间的用户数atomic_tmm_count;// 对mm_struct的引用计数// 5. 其他spinlock_tpage_table_lock;// 保护页表和区域列表的锁structlist_headmmlist;// 连接到所有mm_struct的链表};二、虚拟内存区域vm_area_structVMAVMA的作用每个VMA描述进程地址空间中一段连续的虚拟内存区域具有相同的访问权限和属性。structvm_area_struct{// 区域边界unsignedlongvm_start;// 区域起始地址unsignedlongvm_end;// 区域结束地址// 链接结构structvm_area_struct*vm_next;// 链表下一个VMAstructrb_nodevm_rb;// 红黑树节点// 内存属性unsignedlongvm_flags;// 权限标志读/写/执行等structfile*vm_file;// 如果是文件映射指向文件loff_tvm_pgoff;// 文件中的偏移以页为单位// 操作函数conststructvm_operations_struct*vm_ops;// 其他信息structmm_struct*vm_mm;// 所属的内存描述符};VMA标志vm_flags示例// 常见的权限标志组合#defineVM_READ0x00000001// 可读#defineVM_WRITE0x00000002// 可写#defineVM_EXEC0x00000004// 可执行#defineVM_SHARED0x00000008// 共享映射多进程可见#defineVM_MAYREAD0x00000010// 可能可读#defineVM_MAYWRITE0x00000020// 可能可写#defineVM_MAYEXEC0x00000040// 可能可执行#defineVM_GROWSDOWN0x00000100// 向下增长栈#defineVM_DENYWRITE0x00000800// 禁止对映射文件写入三、进程地址空间的完整视图典型的内存布局高地址 0x7fffffffffff ┌─────────────────┐ │ 栈 │ ← start_stack向下增长 │ │ ├─────────────────┤ ← 栈和堆之间的随机间隙防止溢出 │ │ │ 堆 │ ↑ 向上增长 │ │ ├─────────────────┤ ← brk堆当前结束位置 │ BSS段 │ 未初始化的全局/静态变量 ├─────────────────┤ ← end_data │ 数据段 │ 已初始化的全局/静态变量 ├─────────────────┤ ← start_data │ 代码段 │ 可执行指令 └─────────────────┘ ← start_code (0x400000) 低地址 0x000000000000实际进程的内存映射示例# 查看进程自身的内存映射cat/proc/self/maps# 示例输出64位系统00400000-0040b000 r-xp 00000000 fd:00123456/bin/cat# 代码段只读可执行0060a000-0060b000 r--p 0000a000 fd:00123456/bin/cat# 只读数据0060b000-0060c000 rw-p 0000b000 fd:00123456/bin/cat# 可写数据01c3e000-01c5f000 rw-p 00000000 00:000[heap]# 堆7f8a5a3e1000-7f8a5a5c1000 r-xp 00000000 fd:00789012/lib/x86_64-linux-gnu/libc-2.27.so# 共享库代码7f8a5a5c1000-7f8a5a7c1000 ---p 001e0000 fd:00789012/lib/x86_64-linux-gnu/libc-2.27.so# 保护间隙7f8a5a7c1000-7f8a5a7c5000 r--p 001e0000 fd:00789012/lib/x86_64-linux-gnu/libc-2.27.so# 共享库只读数据7f8a5a7c5000-7f8a5a7c7000 rw-p 001e4000 fd:00789012/lib/x86_64-linux-gnu/libc-2.27.so# 共享库可写数据7f8a5a7c7000-7f8a5a7cb000 rw-p 00000000 00:000# 匿名映射7ffd3d3f6000-7ffd3d417000 rw-p 00000000 00:000[stack]# 栈7ffd3d4ea000-7ffd3d4ed000 r--p 00000000 00:000[vvar]# 内核数据7ffd3d4ed000-7ffd3d4ef000 r-xp 00000000 00:000[vdso]# 虚拟动态共享对象ffffffffff600000-ffffffffff601000 r-xp 00000000 00:000[vsyscall]# 旧系统调用兼容四、内存管理结构在关键操作中的变化1.fork()时的内存管理结构// fork创建子进程时内存管理结构的复制staticintcopy_mm(unsignedlongclone_flags,structtask_struct*tsk){structmm_struct*mm,*oldmm;// 获取当前进程的mm_structoldmmcurrent-mm;if(!oldmm)return0;// 如果是CLONE_VM线程则共享地址空间if(clone_flagsCLONE_VM){atomic_inc(oldmm-mm_users);mmoldmm;}else{// 否则复制mm_struct写时复制mmdup_mm(tsk);if(!mm)return-ENOMEM;}tsk-mmmm;tsk-active_mmmm;return0;}// 复制mm_struct的核心函数staticstructmm_struct*dup_mm(structtask_struct*tsk){structmm_struct*mm,*oldmmcurrent-mm;// 分配新的mm_structmmallocate_mm();// 复制mm_struct的基本字段memcpy(mm,oldmm,sizeof(*mm));// 初始化新的锁和列表INIT_LIST_HEAD(mm-mmlist);mm_init_cpumask(mm);// 复制页表但使用写时复制mm-pgdpgd_alloc(mm);copy_page_range(mm,oldmm);returnmm;}2.exec()时的内存管理结构替换// exec替换地址空间的关键步骤staticintexec_mmap(structlinux_binprm*bprm){structmm_struct*mm,*oldmm;// 创建新的mm_structmmbprm-mm;// 保存旧的mm_structoldmmcurrent-mm;// 切换内存管理结构sync_mm_rss(oldmm);current-mmmm;current-active_mmmm;// 激活新的页表activate_mm(active_mm,mm);// 释放旧的地址空间if(oldmm){up_read(oldmm-mmap_sem);mmput(oldmm);}return0;}五、页表管理连接虚拟与物理内存多级页表结构x86_64虚拟地址 [63:48] 未使用必须全0或全1 [47:39] PML4索引 [38:30] 目录指针索引 [29:21] 目录索引 [20:12] 页表索引 [11:0] 页内偏移 页表层次 CR3寄存器 → PML4表512项 → 页目录指针表512项 → 页目录表512项 → 页表512项 → 物理页框页表项结构// 页表项PTE的位含义structpage_table_entry{unsignedlongpresent:1;// 页是否在内存中unsignedlongrw:1;// 0只读1可写unsignedlonguser:1;// 0内核1用户unsignedlongpwt:1;// 写直达unsignedlongpcd:1;// 缓存禁用unsignedlongaccessed:1;// 是否被访问过unsignedlongdirty:1;// 是否被修改过unsignedlongpat:1;// 页属性表unsignedlongglobal:1;// 全局页TLB不刷新unsignedlongignored:3;// 忽略unsignedlongframe:40;// 物理页框号右移12位unsignedlongreserved:11;// 保留unsignedlongnx:1;// 不可执行位NX};六、内存映射的建立过程mmap系统调用// 用户空间调用mmap映射文件或匿名内存void*mmap(void*addr,size_tlength,intprot,intflags,intfd,off_toffset);// 内核处理流程SYSCALL_DEFINE6(mmap,unsignedlong,addr,unsignedlong,len,unsignedlong,prot,unsignedlong,flags,unsignedlong,fd,unsignedlong,off){// 1. 参数检查if(offset~PAGE_MASK)return-EINVAL;// 2. 调用具体实现returnksys_mmap_pgoff(addr,len,prot,flags,fd,offPAGE_SHIFT);}// 核心实现unsignedlongksys_mmap_pgoff(unsignedlongaddr,unsignedlonglen,unsignedlongprot,unsignedlongflags,unsignedlongfd,unsignedlongpgoff){structfile*fileNULL;// 3. 获取文件描述符对应的文件对象if(fd!-1){filefget(fd);if(!file)return-EBADF;}// 4. 执行映射addrvm_mmap_pgoff(file,addr,len,prot,flags,pgoff);// 5. 清理if(file)fput(file);returnaddr;}七、缺页异常处理缺页异常的类型和处理// 缺页异常处理函数简化版staticinthandle_pte_fault(structvm_fault*vmf){pte_tentry;// 检查页表项if(!pte_present(vmf-orig_pte)){// 页面不在内存中if(pte_none(vmf-orig_pte)){// 1. 匿名页缺页首次访问returndo_anonymous_page(vmf);}else{// 2. 文件映射缺页returndo_fault(vmf);}}// 页面在内存中但访问违规if(pte_protnone(vmf-orig_pte)){// 3. 权限违规如写只读页returndo_numa_page(vmf);}// 其他情况returndo_swap_page(vmf);// 4. 页面被换出到swap}八、内存管理结构的实际观察使用/proc文件系统观察内存结构# 1. 查看进程的内存映射cat/proc/$$/maps# 当前shell的映射cat/proc/1234/maps# PID为1234的进程映射# 2. 查看更详细的内存信息cat/proc/$$/smaps# 每个映射的详细统计大小、RSS等cat/proc/$$/smaps_rollup# 汇总统计# 3. 查看页表信息需要rootcat/proc/$$/pagemap# 虚拟到物理的映射关系二进制格式# 4. 查看内存状态cat/proc/$$/statm# 内存使用摘要# 输出size resident shared text lib data dt# 单位是页通常4KB# 5. 查看内存状态人类可读pmap -x$$# 显示扩展内存信息编写程序观察内存变化#includestdio.h#includestdlib.h#includeunistd.hvoidprint_memory_info(constchar*label){charcmd[100];printf(\n %s \n,label);printf(PID: %d\n,getpid());// 读取/proc/self/mapssnprintf(cmd,sizeof(cmd),cat /proc/%d/maps | head -20,getpid());system(cmd);}intmain(){print_memory_info(程序启动);// 分配堆内存char*heap_memmalloc(1024*1024);// 1MBprint_memory_info(分配堆内存后);// 映射匿名内存char*anon_memmmap(NULL,4096*1024,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0);print_memory_info(映射匿名内存后);// 使用内存触发缺页for(inti0;i1024;i){heap_mem[i]A;anon_mem[i]B;}// 保持进程运行方便查看printf(按回车退出...);getchar();free(heap_mem);munmap(anon_mem,4096*1024);return0;}九、内存管理结构的重要性为什么需要这些复杂结构隔离与保护每个进程有自己的地址空间互不干扰虚拟化让每个进程认为独占整个内存空间效率通过写时复制、按需分页等优化内存使用灵活性支持动态内存分配、文件映射、共享内存等安全性通过权限位读/写/执行防止代码注入等攻击实际应用场景# 1. 调试器如GDB使用ptrace读取/修改目标进程内存# 通过/proc/[pid]/mem接口或ptrace系统调用# 2. 内存分析工具如Valgrind监控内存使用# 通过拦截内存分配和访问函数# 3. 容器技术如Docker控制进程内存使用# 通过cgroups设置内存限制内核在mm_struct中跟踪使用量# 4. 进程转储core dump# 保存进程的完整地址空间到文件供事后分析十、总结内存管理结构是操作系统的核心基础设施它抽象物理内存为每个进程提供独立的虚拟地址空间管理资源跟踪哪些内存区域已分配、如何使用提供保护通过权限控制防止非法访问支持优化实现共享内存、写时复制等高级特性连接文件系统支持内存映射文件这些结构在fork()、exec()、mmap()等关键操作中被创建、复制、修改和销毁构成了进程内存管理的基石。理解它们对于深入理解操作系统工作原理、进行系统编程和性能优化都至关重要。