内存管理子系统架构
内存管理子系统架构可以分为:用户空间、内核空间及硬件部分3个层面,具体结构如
下图所示:
1、用户空间:应用程序使用malloc()申请内存资源/free()释放内存资源。
2、内核空间:内核总是驻留在内存中,是操作系统的一部分。内核空间为内核保留,不允许应用程序读写该区域的内容或直接调用内核代码定义的函数。
3、硬件:处理器包含一个内存管理单元 (Memory Management Uint,MMU)的部件,负责把虚拟地址转换为物理地址。
下面的这个架构图 但是就为了说明 中间有个系统调用在kernel和app的c库之间 在内核层
内核空间模块分布图
简单把内核氛围下面的模块
Process shedule 进程管理调度运行
Mem 内存管理调度 负责内存资源
Ipc 系统中进程间通信
VFS 虚拟文件系统,把磁盘硬盘进行抽象,通过统一的文件接口进行操作
Net 网络子系统 管理网络设备 各种网络标准
Dev 驱动
app通过各种系统调用在用户空间操作到内核空间
用内存开辟举个例子,看看app怎么通过系统调用操作到内核
比如应用程序app需要开辟空间 需要通过c的一些标准函数 malloc new free等 操作到各种库提供的函数
这些函数使用系统调用 sys_brk来继续进行内存的分配
到虚拟内存管理 页错误异常处理 页表管理 内存控制 内存碎片整理 页回收 内存耗尽
分配器 都是这些内核里面的模块
1、用户空间
相当于应用程序使用malloc()申请内存,通过free0释放内存。malloc()/free()是 glibc库的内存分配器ptmalloc提供的接口,
ptmalloc使用系统调用brk或mmap向内核以页为单位申请内存,然后进行分成很小内存块分配给对应应用程序。
2、内核空间
虚拟内存管理负责从进程的虚拟地址空间分配虚拟页, sys_brk来扩大或收缩堆,sys mmap用来在内存映射区域分配虚拟页,
sys munmap用来释放虚拟页。页分配器负责分配物理页,使用分配器是伙伴分配器
内核空间扩展功能,不连续页分配器提供分配内存的接口vmalloc和释放内存接口vfree。在内存碎片化的时候,申请连续物理页的成功
比较低,可以申请不连续的物理页,映射到连续的虚拟页,即虚拟地址连续而物理地址不连续。
内存控制组用来控制进程占用的内存资源。当内存碎片化的时候,找不到连续的物理页,内存碎片整理通过迁移方式得到连续的物理
页。在内存不足的时候,页回收负责回收物理页。
3、 硬件
MMU包含一个页表缓存, 保存最近使用过的页表映射,避免每次把虚拟地址转换为物理地址都需要查询内存中的页表。解决处理器执行速
度和内存速度不匹配问题,中间增加一个缓存。一级缓存分为数据缓存和指令缓存。 二级作用协调一级缓存和内存之间的工作效率。
代码详解
所以代码在系统调用中怎么传递的
在执行结果看看内存分配的对应地址
使用cat /proc/进程号/maps 找到对应进程的一个内存分布图
下面的heap(堆)中的内存分布和代码中创建的一样
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main(int argc, char* argv[])
{// 使用 sbrk 系统调用申请 堆内存int *p = sbrk(0);// 记录该堆内存地址int *p_old = p;// 继续为 申请的堆内存, 申请 1024 字节内存p = sbrk(1024);// 打印进程 ID , PID printf("pid : %d\n", getpid());// 打印 申请的 堆内存地址 , 发现地址没有变化printf("p_old : %p \np : %p \n", p_old, p);// 申请新的 堆内存int *p_new = sbrk(0);// 打印新的 堆内存地址printf("p_new : %p\n", p_new);// 此处死循环阻塞, 方便查看 /proc/pid/maps 中的信息// 进程退出后 , 进程相关内存信息也会同时销毁while (1);return 0;
}
sbrk 返回的指针 p , 在第二次申请内存时 , 指针始终没有改变 , 一直都是 0x0000 557f fee6 6000 地址 ;
如果使用新的指针 p_new 接收 sbrk 系统调用返回的堆内存指针 , 则分配的是新的地址 ;