您的位置:首页 > 产品设计 > UI/UE

APUE_内存管理

2016-01-24 10:10 555 查看

1.进程 中的内存模型

虚拟内存管理技术

unix/linux系统中的内存管理技术是采用虚拟内存管理技术进行管理的,即:每个进程都可一有0~4G的地址空间(虚拟的,并不是真是存在的),由操作系统负责把虚拟地址和真实的物理内存映射起来的(内存地址是以字节为基本单位,但是内存的映射是以内存页为基本单位的,目前主流的操作系统内存页大小是4kb(4096个字节),因此,不同进程的地址空间看起来是一样的,但所对应的真实物理内存并不是一样的。

对于每个进程中的虚拟地址空间来说,分为两部分:用户空间和内核空间

其中0~3G之间的虚拟内存叫做用户空间,而3~4G之间的虚拟地址叫做内核空间;

用户程序一般都运行在用户空间中,内核空间只有系统内核才可以访问,用户程序不能直接访问,但可以通过内核提供的API函数访问。



一般来说,堆区的内存地址从小到大分配,而栈区的内存地址从大到小分配,堆区和栈区之间的距离较远,本质上是因为堆区和栈区之间没有明显的分割线,避免区域重合。

2.内存管理的相关函数

1.sbrk函数

#include <unistd.h>
void *sbrk(intptr_t increment);


函数功能:

主要用于修改数据段的大小.

参数:当参数 >0时,则申请动态内存,当参数 = 0时,获取当前的内存块位置,当参数 <0时;则释放动态内存空间

返回值:成功返回之前的内存块地址;失败返回(void*)-1,sbrk(0)返回的是当前内存块的末尾地址

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

int main (viod){

void *p1=sbrk(4);
void *p2=sbrk(4);
void *p3=sbrk(4);
void *p4=sbrk(4);
printf("p1=%p,p2=%p,p3=%p,p4=%p\n",p1,p2,p3,p4);
void *cur=sbrk(0);
printf("cur = %p\n",cur);

void *p5=sbrk(-4);
printf("p5=%p\n",p5);
cur = sbrk(0);
printf("cur = %p\n",cur);

return 0;

}


运行结果:



sbrk 函数的工作方式(一般性原则)

当使用sbrk函数申请比较小的内存时,系统会一次性分配1个内存页大小的空间,如果申请的内存超过1个内存页的范围,则再次分配一个内存页(也就是按照1个内存页的整数倍

管理)

使用sbrk函数释放内存时,如果剩下的内存可以用1个内存页表示则一次性回收一个内存页的空间(也就是按照1个内存页的整数被管理)

当所有内存释放完毕后,系统不再保留内存空间。

注意:使用sbrk函数申请内存比释放内存更方便一些。

2. brk函数

#include <unistd.h>
int brk(void *addr);


函数功能:

主要根据参数指定的目标地址调整内存地址,如果目标地址>起始地址,表示申请内存,如果目标地址=起始地址,表示内存空家不变;如果目标地址<起始地址,则表示释放内存;其中最开始的起始地址由操作系统指定。

注意:使用brk函数释放内存比较方便,因此一般情况下与sbrk函数搭配使用,sbrk负责申请内存,brk负责释放内存.

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

int main(void){

void *p=sbrk(0);
printf("p=%p\n",p);
int res=brk(p+4);
if(-1 == res){

perror("brk"),exit(-1);
}
void *cur=sbrk(0);
printf("cur=%p\n",cur);
brk(p+8);
cur=sbrk(0);
printf("cur=%p\n",cur);
return 0;
}




3.getpagesize函数

int gfetpagesize(void)


函数功能:获取内存页的大小,一般为4KB

4.mmamp函数

include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);


Para1:建立映射的起始地址,给null表示由内核指定。

Para2:映射的大小,基本单位是内存页

Para3:映射的访问权限(不要和文件的打开方式冲突),

PROT_EXEC :可执行
PROT_READ :可读
PROT_WRITE :可写
PROT_NONE :不可访问


表示映射的标志,是否对其他进程可见

MAP_SHARED:共享的

MAP_PRIVATE:私有的

MAP_ANONYMOUS:映射到物理内存(忽略参数fd和offset)

Para5:文件描述符,暂时给0即可。

Para6:文件中的偏移量,暂时给0即可。

返回值:成功返回映射的地址,失败返回MAP_FAILED(-1)

函数功能:主要建立/解除 文件/设备 到内存的映射

5.munmap函数

int munmap(void *addr, size_t length);


函数功能:主要用于根据参数指定的映射地址的大小进行映射解除。

#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>

int main(void){

void *p=mmap(NULL,4,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,0,0);
if(p ==-1)
{
printf("mmap"),exit(-1);

}

int *pi=p;
*pi=200;
printf("*pi=%d\n",*pi);
int res = munmap(p,4);
if(res == -1)
{
printf("munmap"),exit(-1);

}
printf("解除映射成功");
return 0;

}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: