Unix/Linux的内存分配

程序员所接触的都是虚拟内存地址。每个进程都有0-4G的虚拟内存地址,本质上就是一个整数。这个整数

先天是不能够存储数据的,否则会引发段错误。虚拟内存地址,只有映射零物理内存/硬盘文件后,才能存

储数据,才占据内存。

虚拟内存地址分为用户空间和内核空间。0-3G为用户空间,3-4G是内核空间。用户空间不能直接访问内核空间,但可以通过系统提供的函数进入内核空间。内存地址的基本单位是字节,内存映射的基本单位是内存页,一个内存页是4k(或者4k的倍数)。

内存分配和回收的函数(运算符)
STL          -》 自动分配,自动回收
|
C++          -》new ,delete
|
c语言        -》malloc() free()
|
Unix系统函数 -》brk() sbrk()
|
Unix系统函数 -》mmap(),munmap()           用户层
————————————————————————————
     |
Unix系统函数 -》kmalloc()                 内核层

1)malloc 和 free

malloc只有在第一次时映射内存,一次映射33个内存页。如果用完, 才再次映射。
如果系统映射超过33页,系统就会映射稍多一点内存。

需要注意的是:

malloc分配内存时,系统会额外占用一些空间,用于存储下一个空间的 附加信息。

	int *p1 = malloc(4); //内存映射,映射33个内存页
	int *p2 = malloc(4);//只分配,不再映射内存
	int *p3 = malloc(4);
	int *p4 = malloc(12);
	printf("%p %p %p %p \n",p1,p2,p3,p4);//堆之间的地址并没有连续
//p1地址前面存放着附加信息,将附加信息清零  ==》错误:已放弃,核心已转移	
	*(p1 -1) = 0; 。
        free(p1);
free()一定释放虚拟内存,但是不保证解除物理内存的映射,而且最后的33个内存页是无法free的,进程
结束才能解除最后的33个内存页。为了提高效率, 用空间换时间。

例如,我首先分配内存

void *p = malloc(1);//此时系统一次性映射了33个内存页
free(p);  //此时并没有解除物理内存的映射.

2) sbrk 和 brk

sbrk()和brk()底层维系了一个位置。通过位置的移动来分配和回收内存。
void sbrk(intptr_T increment)

increment 移动增量负数逆向移动(释放内存),正数向前移动(分配内存),

为0返回当前位置。成功返回移动之前的位置,失败返回零。
sbrk实打实的每次一次分配一页空间,如果超出一页就再分配一页。

        char *p_num = sbrk(4);//分配了四个字节的内存,返回首地址
	*p_num = 100;
	printf("%d\n",*p_num);  //打印出100
	sbrk(-4);//释放3个字节内存,返回值没有意义
brk 函数决定了所分配空间的结尾地址.如下:

	void *p = sbrk(0);//返回当前地址,并不映射内存。
	brk(p+4); //分配了四个字节,映射了一页地址。
	brk(p+8); //重新分配四个字节
	brk(p+4);//回收四个字节 
sbrk用来分配内存方便,而brk用来释放内存更方便.(两个函数都可以用来分配和释放内存)
//分配空间存放int
	int *pi = (int*)sbrk(4);
	*pi = 100;
//分配空间存放double
	double *pd = (double*)sbrk(8);
	*pd = 1.0;
//分配空间存放string
 	char *p_str = (char*)sbrk(6);
	strcpy(p_str,"abcde");
//释放所有空间
	brk(pi);
3)mmap,munmap

用来映射或者取消映射.代码如下:

#include<sys/mman.h>
#include<unistd.h>
#include<string.h>
int main()
{
	void *p_map = mmap(0,  //内核选择虚拟首地址
	1,  //映射的字节数,不足内存页补足
	PROT_READ | PROT_WRITE,//读写权限
	MAP_SHARED | MAP_ANONYMOUS,//共享,匿名
	-1,0);  //映射一页内存
	if( p_map == MAP_FAILED)
	{
		perror("mmap");
		return -1;
	}
	int *pi = p_map;
	*pi = 100;

	strcpy(pi + 4,"kongdeju"); //证明映射了一页。
	printf("%d,%s\n",*pi,(char*)(pi + 4));
	munmap(p_map,1);//取消映射
	return 0;
}




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值