虚拟内存管理回顾在 linux 操作系统中,虚拟地址空间的内部又被分为内核空间和用户空间两部分,不同位数的系统,地址空间的范围也不同 。比如最常见的 32 位和 64 位系统,如下所示:
文章插图
通过这里可以看出:
- 32 位系统的内核空间占用 1G,位于最高处,剩下的 3G 是用户空间;
- 64 位系统的内核空间和用户空间都是 128T,分别占据整个内存空间的最高和最低处,剩下的中间部分是未定义的 。
- 进程在用户态时,只能访问用户空间内存;
- 只有进入内核态后,才可以访问内核空间的内存;
文章插图
我们看看用户空间分布的情况,以 32 位系统:
文章插图
通过这张图你可以看到,用户空间内存,从低到高分别是 6 种不同的内存段:
- 0x0000 0000 到 0x0804 8000 这段虚拟内存地址是一段不可访问的保留区,因为在大多数操作系统中,数值比较小的地址通常被认为不是一个合法的地址,这块小地址是不允许访问的 。比如在 C 语言中我们通常会将一些无效的指针设置为 NULL,指向这块不允许访问的地址 。
- 代码段,包括二进制可执行代码;
- 数据段,包括已初始化的静态常量和全局变量;
- BSS 段,包括未初始化的静态变量和全局变量;
- 堆段,包括动态分配的内存,从低地址开始向上增长;
- 堆空间的上边是一段待分配区域,用于扩展堆空间的使用
- 文件映射段,包括动态库、共享内存等,从低地址开始向上增长
- 栈段,包括局部变量和函数调用的上下文等 。栈的大小是固定的,一般是 8 MB 。当然系统也提供了参数,以便我们自定义大小;
malloc的调用规律1. 即分配一块小型内存(小于或等于128kb),malloc()会调用brk 函数将 堆顶 指针向高地址移动,获得新的内存空间 。
2. 当分配一块大型内存(大于128kb),mmap() 系统调用中「私有匿名映射」的方式,在文件映射区分配一块内存
申请内存过程图
文章插图
需要注意的是,malloc() 分配的是虚拟内存 。
如果分配后的虚拟内存没有被访问的话,虚拟内存是不会映射到物理内存的,这样就不会占用物理内存了 。
只有在访问已分配的虚拟地址空间的时候,操作系统通过查找页表,发现虚拟内存对应的页没有在物理内存中,就会触发缺页中断,然后操作系统会建立虚拟内存和物理内存之间的映射关系 。
缺页中断就是要访问的页不在主存,需要操作系统将其调入主存后再进行访问 。在这个时候,被内存映射的文件实际上成了一个分页交换文件 。
malloc 申请的内存,free 释放内存会归还给操作系统吗
- malloc 通过 brk() 方式申请的内存,free 释放内存的时候,并不会把内存归还给操作系统,而是缓存在 malloc 的内存池中,待下次使用;
- malloc 通过 mmap() 方式申请的内存,free 释放内存的时候,会把内存归还给操作系统,内存得到真正的释放 。
也就是说,频繁通过 mmap 分配的内存话,不仅每次都会发生运行态的切换,还会发生缺页中断(在第一次访问虚拟地址后),这样会导致 CPU 消耗较大 。
为了改进这两个问题,malloc 通过 brk() 系统调用在堆空间申请内存的时候,由于堆空间是连续的,所以直接预分配更大的内存来作为内存池,当内存释放的时候,就缓存在内存池中 。
推荐阅读
- 图像描述的视觉关系
- durex是什么意思英文 durex是什么意思
- 领导提拔你,从来不是看努力
- 江珊:我这辈子最正确地决定,就是再婚嫁演员
- “一代国师”跌落神坛,晚节不保,文艺人设竟然都是伪装
- 《灼灼风流》慕灼华有3张王牌,大结局显然是要稳赢了
- 鹊刀门传奇:自古公公好威名!高大毛算什么,曹公公才是反派1号
- 汪字兰的养殖方法和注意事项是什么 汪字兰的养殖方法和注意事项
- 飞蟹怎么储存活的 飞蟹怎么储存
- 肥胖不过是痰湿太重,简单两味药,一消一补,减重42斤!