Linux中的程序都是在进程中执行的,而每个进程都有自己的虚拟地址空间,进程中的内存操作,比如访问,插入数据都是在这块虚拟地址空间上操作的。
虚拟地址空间
虚拟地址空间是一个进程所使用的虚拟内存地址的集合,每个进程都有自己独立的虚拟地址空间。
虚拟地址空间由操作系统管理,可以分为多个部分,如代码段、数据段、堆栈等。
程序员在编写代码时可以使用虚拟地址,而不必考虑物理内存的实际位置。
当程序被执行时,操作系统将虚拟地址转换为物理地址,以便访问实际内存。
虚拟地址空间的好处是可以让多个进程共享同一份代码,同时还能够保护进程间的内存访问,增强系统的安全性和稳定性。
虚拟地址空间的功能
内存隔离:进程A可以在其虚拟地址空间中创建一个大型数组,而不会干扰其他进程的内存。进程B也可以创建一个相同大小的数组,但它在自己的虚拟地址空间中,两个进程的数组相互隔离。同一个线程组的用户线程共享用户虚拟地址空间,内核线程没有用户虚拟地址空间。
内存映射:当进程A访问其虚拟地址空间中的数组元素时,操作系统将虚拟地址映射到物理内存中相应的地址。例如,虚拟地址0x1000可能映射到物理内存地址0x4000。进程A无需知道具体的物理内存地址,只需要通过虚拟地址访问数组。这里需要用到内存管理单元中的页表缓存部件中的页表映射,将虚拟地址转换为物理地址。而页表映射就是通过页表项实现的,可以将页和对应物理地址对应起来。
虚拟内存管理:虚拟内存管理:假设数组的大小超过了可用的物理内存大小。在这种情况下,操作系统可以将虚拟地址空间中未被使用的部分保存在磁盘上的交换文件中。当进程A需要访问被交换出的数据时,操作系统会将其重新加载到物理内存中,这样进程A可以继续访问它。通过这种虚拟内存管理技术,进程A可以使用比物理内存更大的地址空间。
内存保护:操作系统可以为进程A的虚拟地址空间设置访问权限。例如,操作系统可以将数组的某个区域设置为只读,以防止进程A在不经过授权的情况下修改数据。这提供了一定的安全性和数据完整性保护。
虚拟内存
虚拟内存更多被定义为一项操作系统的内存管理技术,它将虚拟地址空间和物理内存结合起来,扩展了可用的内存空间。虚拟内存将虚拟地址空间中的部分数据暂时保存在硬盘上的交换文件中,而不是全部存储在物理内存中。这样,即使实际的物理内存有限,进程仍然可以访问大于物理内存大小的数据。
物理内存
物理内存是计算机中实际存在的内存,也称为硬件内存或主存储器。它是由芯片组成的硬件设备,用于存储正在运行的程序和数据。计算机需要将数据从硬盘等外部存储设备读取到物理内存中,才能通过CPU进行处理和操作。物理内存的大小直接影响计算机的性能和运行速度。
虚拟内存地址空间布局
虚拟内存地址空间又分用户空间和内核空间,其中用户空间是程序员通过代码分配使用,内核空间的使用来源于CPU的调度处理。
1.用户空间
应用程序使用malloc()申请内存,使用free()释放内存,malloc()/free()是glibc 库的内存分配器ptmalloc 提供的接口,ptmalloc 使用系统调用brk/mmap 向内核以页为单位申请内存,然后划分成小内存块分配给用户应用程序。
2.内核空间
内核空间的基本功能:虚拟内存管理负责从进程的虚拟地址空间分配虚拟页,sys_brk 用来扩大或收缩堆,sys_mmap 用来在内存映射区域分配虚拟页,sys_munmap 用来释放虚拟页。
页分配器负责分配物理页,当前使用的页分配器是伙伴分配器。内核空间提供把页划分成小内存块分配的块分配器,提供分配内存的接口kmalloc()和释放内存接口kfree()。块分配器:LAB/SLUB/SLOB。
3.硬件层面
处理器包含一个称为内存管理单元(Memory Management Unit,MMU)的部件,负责把虚拟地址转换成物理地址。内存管理单元包含一个称为页表缓存(Translation Lookaside Buffer,TLB)的部件,保存最近使用的页表映射,避免每次把虚拟地址转换物理地址都需要查询内存中的页表。
用户虚拟地址空间布局
Linux 内核使用内存描述符mm_struct 描述进程的用户虚拟地址空间,每个进程在内核中都有一个对应的mm_struct结构。
mm_struct结构包含了与进程内存管理相关的信息,其中一些重要的字段包括:
- pgd:指向进程页表的指针。页表用于将虚拟地址映射到物理地址,pgd存储了页表的基地址。
- mmap:链表结构,记录了进程当前所拥有的内存映射区域。每个内存映射区域都包含了起始地址、结束地址、权限标志等信息。
- mm_rb:红黑树结构,用于快速查找和管理进程的虚拟地址空间。
还有代码段、数据段、堆、栈的起始/结束地址等参数成员。
同一个线程组的用户线程共享用户虚拟地址空间,因为线程组是同一个进程的一组线程,他们共享进程资源,比如内存空间、文件描述符等。
内核线程是没有用户虚拟地址空间的,因为内核线程不属于任何用户线程,内核线程是操作系统内核的一部分,它们在内核空间运行,负责处理系统任务和管理硬件资源。只有内核虚拟地址空间,内核虚拟地址空间通常是操作系统的一部分,与用户进程的虚拟地址空间分开管理。