Linux虚拟内存映射之brk/sbrk,map/munmap

本文介绍了Linux虚拟内存的概念,包括逻辑地址与物理地址的映射,以及两种内存分配方式:brk/sbrk函数用于动态分配和释放堆内存,mmap/munmap则用于内存映射。讨论了brk/sbrk的使用,如sbrk(0)获取未映射空间的首地址,并通过调整指针进行内存分配。同时提到了mmap用于匿名映射和文件映射,及其参数详解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.关于虚拟内存

         问题:

                   一个程序不能访问另外一个程序的地址指向的空间.

         理解:

                   1.每个程序的开始地址ox8048000(?可由objdump 反汇编得到)

                   2.程序中使用的地址不是物理地址,而是逻辑地址(虚拟内存).

                     逻辑地址仅仅是编号.编号使用int 4字节整数表示.

                     4294967296=4G

                     每个程序提供了4G的访问能力(32位机,下同)

         问题:

                   逻辑地址与物理地址关联才有意义:过程称为内存映射.

         背景:

                   虚拟内存的提出:禁止用户直接访问物理存储设备.

                   有助于系统的稳定.

                                              

         结论:

                   虚拟地址与物理地址映射的时候有一个基本单位:至少会映射4K

                                     4k  1000 内存页.

                   段错误:无效访问. 那段内存没有映射

                   合法访问:比如malloc分配的空间之外的空间可以访问,但访问非法.因是越界访问

 

                   内存访问分两种:一个是可以访问,但不一定是合法的,比如malloc几个字节,

                   内存会给你映射4K空间,int*p=malloc(0); *(p+1000)=9999;理论说这是可以访问,但是非法的,它可能破坏维护malloc分配的数据结构,就跟虚表指针一样。

 

二.虚拟内存的分配

                   栈:编译器自动生成代码维护

                   堆:地址是否映射?映射的空间是否被管理?

1.brk/sbrk内存映射函数

分配释放内存:                

                            int brk(void *end);//分配空间,释放空间

                            void *sbrk(int size);//返回空间地址

                            应用:

                                     1.使用sbrk分配空间

                                     2.使用sbrk得到没有映射的虚拟地址.

                                        第一次调用sbrk,sbrk(0)得到的是没有映射的虚拟首地址。

                                     3.使用brk分配空间

                                     4.使用brk释放空间

                            理解:

                                     sbrk(int  size)

                                     如果是第一次运行,则返回没有映射的空闲空间首地址,同时产生一个数据:指向地址

 

                                     sbrk与brk后台系统维护一个指针.

                                     指针默认是null.

                                    调用sbrk,判定指针是否是0,

 是:得到大块空闲空间的首地址初始化指针.同时把指针+size                               

                                         否:返回指针,并且把指针位置+size

demo:

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

main()
{
	int *p=sbrk(0); //返回的是空闲空间的首地址,然后系统给映射一个页
	//*p=800;  //段错误
	int *p1=sbrk(4);//返回空闲地址,然后系统给映射4K  并修改指针为+size
					//先看一下指针是否为空,如果是空,就返回空闲空间的首地址,
					//然后再看里面的参数是几个字节,再看一下这几个字节是否有空间,
					//没空间的话就映射空间,然后把指针+4
	*(p1+10)=4000; //可以访问,反正系统给映射了4K空间大小,但是是非法的

	int *p2=sbrk(0);  //返回的是首地址+4
  
	p2=sbrk(200);
	int *p3=sbrk(0); //得到的地址是首地址+204

	int *p4=sbrk(-4);//释放4个字节的空间
	int *p5=sbrk(-4);
	printf("%p\n",p);	
	printf("%p\n",p1);
	printf("%p\n",p2);
	printf("%p\n",p3);
	printf("%p\n",p4);
	printf("%p\n",p5);
	printf("%d\n",getpid());
	
	/*
	int *p=sbrk(0);
	brk(p+1);//brk改变的是绝对位置
	*p=800;
	*/
	brk(p);
	
	//*p=99;//段错误
	
	//while(1);
}

/*输出:
0x8909000
0x8909000
0x8909004
0x89090cc
0x89090cc
0x89090c8
15945
*/

                            应用案例:

                                     写一个程序查找1-10000之间所有的素数.

                                     并且存放到缓冲,然后打印.

                                              

                                     缓冲的实现使用sbrk/brk

                                     流程:

                                               循环

                                                        判定是否素数(isPrimer)

                                                        是,分配空间存放

                                                        不是,继续下步.

#include <stdio.h>
#include <unistd.h>
int isPrimer(int a)
{	
	int i;
	for(i=2;i<a;i++){
		if(a%i==0) 
			return 1;
	}
	return 0;
}

main()
{
	int i=2;
	int b;
	int *r;
	int *p;
	p=sbrk(0);
	r=p;
	for(;i<100;i++){
		b=isPrimer(i);
		if(b==0){
			brk(r+1);
			*r=i;
			r=sbrk(0);
		}
	}
	
	i=0;
	r=p;
	while(r!=sbrk(0)){
		printf("%d\n",*r);
		r++;
	}
	brk(p);//free
}

2.mmap/munmap内存映射函数

没有任何额外维护数据的内存分配。

                   mmap(分配)/unmap(释放)

                   1.函数说明

                   void *mmap(

                            void *start,//指定映射的虚拟地址 0由系统指定开始位置)

                            size_t length,//映射空间大小pagesize倍数

                            int prot,//映射权限  PROT_NONE | PROT_READ PROT_WRITE PROT_EXEC

                            intflags,//映射方式

                            int fd,//文件描述符号

                            offset_t off);//文件中的映射开始位置(必须是pagesize的倍数)

                           

                            映射方式:

                                               内存映射:匿名映射。

                                               文件映射:映射到某个文件

                                                                                      只有文件映射最后两个参数有效。

                                              

                                               MAP_ANONYMOUS

                                               MAP_SHARED   MAP_PRIVATE(二选一)

2.demo

#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <stdio.h>
main()
{
	int *p=mmap(
		NULL,
		getpagesize(),
		PROT_READ,
		MAP_ANONYMOUS|MAP_SHARED,
		0,0);
	*p=20;
	*(p+1)=30;
	*(p+2)=40;
	
	printf("%d\n",p[2]);
	munmap(p,4096);
}


三.总结:

智能指针(指针池)

                   STL                     

                   new          

                   malloc (小而多数据)

                   brk/sbrk (同类型的大块数据,动态移动指针)

                   mmap/munmap(控制内存访问/使用文件映射/控制内存共享)


                            异常处理

                                     int brk(void*)

                                     void *sbrk(int);

                                     如果成功.brk返回0   sbrk返回指针

                                     失败 brk返回-1  sbrk返回(void*)-1
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值