malloc是函数而不是系统调用,他的底层是同调调用brk和mmap这两个系统调用实现功能的,具体选择brk还是mmap要看申请的空间大小以及malloc中的阈值(一般是128kb)
注意申请的空间只有使用才会触发缺页中断映射到物理内存
不理解的话先去学习一下分页和分段这些概念
brk
特点
- 进行堆指针的偏移
- 申请的空间会比申请的大
- 容易产生内存碎片
- 空间释放后不会返回给操作系统而是给内存池
- 维持了内存池从而减少了系统调用
mmap
特点
- 申请的空间大
- 申请的空间释放后回归操作系统而非内存池
- 从文件映射区挖一块内存
brk相较于mmap适合用作小空间处理的原因可以从两方面理解
- brk的原理是移动堆指针,地址连续用着用着会产生大量的内存碎片,性能提升不会太高
- 减少对操作系统并发性的影响,大空间被挖走当内存池会影响操作系统的整体性能
free释放时是如何知道释放多大空间的
在malloc的前边几个字段会存储申请的空间大小,释放的时候会偏移回去,可以借助指针看看,空间大小一般会比申请的大
#include<iostream>
#include<stdlib.h>
using namespace std;
int main(){
int *cur=(int*)malloc(32);
for(int i=0;i<8;i++) cur[i]=i;
for(int i=-5;i<15;i++){
cout<<*(cur+i)<<endl;
}
}
可以看到这里的实际大小是奇数,计算一下,堆的对齐方式是16字节,头部8字节,多申请一位应该是为了避免你申请8字节时出现堆指针和内存重叠的情况,你细品
内存不够用时申请物理内存会发生什么
如果没有空闲的物理内存,那么内核就会开始进行回收内存的工作,回收的方式主要是两种:直接内存回收和后台内存回收。
- 后台内存回收:在物理内存紧张的时候,会唤醒 kswapd 内核线程来回收内存,这个回收内存的过程异步的,不会阻塞进程的执行。
- 直接内存回收:如果后台异步回收跟不上进程内存申请的速度,就会开始直接回收,这个回收内存的过程是同步的,会阻塞进程的执行。
- 如果直接内存回收后,空闲的物理内存仍然无法满足此次物理内存的申请,那么内核就会触发 OOM机制,OOM机制会根据
页面置换算法
选择一个占用物理内存较高的进程,然后将其杀死,以便释放内存资源,如果物理内存依然不足,OOM会继续杀死占用物理内存较高的进程,直到释放足够的内存位置。
回收对象
- 文件页,缓存磁盘数据/缓存文件数据等,如果修改过没有提交是脏页需要进行页面置换,否则的话一般认为可以直接释放
- 匿名页,比如栈、堆数据,这类必须要进行页面置换
所以说当申请的空间大于实际拥有的内存量时需要进行大量的文件IO会变得非常的卡,可以设置回收倾向来适当缓解,一般推荐优先回收文件页