遵循POSIX标准的内存管理API:
#include <unistd.h>
// brk和sbrk在内部维护一个指针p(void*),p指针指向当前堆内存中已经映射成功的最后一个字节的下一个地址位置
void *sbrk(intptr_t increment);
功能:根据参数increment来调整p的位置,既可以映射内存,也可以取消映射
incremen:移动增量
>0 p+incremen 映射内存
0 p 获取p的位置
<0 p+incremen 取消映射
返回值:移动前,p指针的位置
int brk(void *addr);
功能:通过直接移动p到addr地址位置,来映射和取消映射
addr: 直接移动到的位置
> p 映射内存
< p 取消映射
返回值:成功0 失败-1
注意:sbrk和brk都可以单独映射、取消映射,但是一般都会配合一起使用,通过sbrk映射内存,通过brk取消映射
注意:sbrk和brk只能对虚拟内存进行映射、取消映射,无法做到精细化管理,只是维护一个位置指针
Linux系统提供的内存管理函数:
#include <sys/mman.h>
// mmap和munmap底层不维护任何东西
// 通过mmap映射内存,是以一页为单位来映射的
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
功能:
1、用户空间的虚拟内存与物理内存建立映射关系
2、用户空间的虚拟内存与文件建立映射关系
addr:想要映射的虚拟内存的首地址,如果是NULL,则由操作系统自动计算
length:要映射的字节数
prot:映射后的内存权限
PROT_EXEC 执行权限
PROT_READ 读权限
PROT_WRITE 写权限
PROT_NONE 无权限
如果要有多个权限,进行按位或操作
flags:设置参数
MAP_SHARED 共享映射,映射的内容对其它进程是可见的,如果此时映射给文件,相当于可以输出到文件中
MAP_PRIVATE 私有映射,映射的内容其它进程不可见
MAP_ANON 拒绝对文件进行映射,会忽略fd、offset参数
MAP_FIXED 如果提供了addr无法进行映射,则直接失败,系统不会自动调整
fd:文件描述符,类似于文件指针,如果不使用则给0即可
offset:映射文件后从该偏移值开始操作文件
返回值:映射成功后的虚拟内存首地址,失败返回0xFFFFFFFF
int munmap(void *addr, size_t length);
功能:取消映射
addr:已经映射的内存首地址
length:内存字节数
返回值:成功0 失败-1
#include <stdio.h>
#include <sys/mman.h>
int main(int argc,const char* argv[])
{
FILE* fp = fopen("t.txt","r+");
if(NULL == fp)
{
perror("fopen");
return -1;
}
// 转换成文件描述符
int fd = fileno(fp);
printf("----\n");
char* str = mmap(NULL,100,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_FILE,fd,0);
printf("----\n");
if((void*)-1 == str)
{
perror("mmap");
return 0;
}
// 往映射后的虚拟内存写入数据
printf("----%s\n",str);
sprintf(str,"hello worldxxxxxxxxxxiid\n");
// str[0] = 'a';
// 取消映射
munmap(str,100);
fclose(fp);
}
内存管理总结:
-
mmap、munmap底层不维护任何东西,只会返回映射后的内存首地址
-
brk、sbrk底层维护一个位置指针,通过该指针的位置决定映射、取消映射
-
每个进程都有4G的虚拟内存,所有的虚拟内存编号都是一个数字而已,必须与物理内存建立映射后才能使用,否则段错误
-
平时所说的内存的申请和释放有两层含义
-
权限的分配和回收
-
映射关系的建立和取消
-