内存分配(mmap用法)

Linux用户空间内存分配

void *malloc(size_t nbytes)//返回指向nbytes个字节内存的指针
viod *calloc(size_t cnt, size_t nbytes)//返回指向cnt* nbytes的空间(内容为0)的指针(即分配之后自动清零)
void *realloc(void *ptr, size_t size)//改变前面分配的空间大小
void free(void *ptr)//释放动态分配的内存空间

Linux内核空间内存分配

按页分配函数:

unsigned long	__get_free_page(int gfp_mask)
unsigned long	__get_free_pages(int gfp_mask, unsiged long order)
//所分配的内存在物理上是连续的
//“_“表示 在返回页时并不将其清0
/*该函数可分配多个页并返回分配内存的首地址,分配的页数为2order,分配的页也不清零。
order允 许的最大值是10 (即1024页)或者11 (即2048页),依赖于具体的硬件平台。*/
void free_page(unsigned long addr)
void free_pages(unsigned long addr, unsigned long order)
//必须自己释放内存.
//在模块卸载时内核并不清楚其拥有的页

kmalloc和vmalloc:

1.内核管理物理内存方式在底层是通过页来实现的
2.内核为了满足任意数量的内存使用请求,创建了由各种不同固定大小的内存块组成的内存对象池
3.当kmalloc申请内存空间时,内核就会将一个刚好足够大的空闲内存块分配出来。比如要申请100字节,kmalloc就会返回一个128字节的内存块
4.在4k字节大小页面的系统上,分配的最小内存块是32字节最大128k字节
5.分配的物理空间是连续的
6.调用接口
void *kmalloc(size_t size, int flags);
void kfree(void *addr)

1.vmalloc函数用来分配虛拟地址空间的连续区域
2.vmalloc函数获得的连续虚拟地址空间在物理地址上可能是不连续的
3.vmalloc函数获得的地址是平台相关的
4.不能在中断时分配
5.调用接口
void *vmalloc(unsigned long size)
void vfree(void *addr)

mmap 文件映射到内存
mmap是把文件内容映射到进程的虚拟内存空间, 通过对这段内存的读取和修改,来实现对文件的读取和修改,而不需要再调用read,write等操作
为什么用mmap
1. 用mmap替代文件操作(read,write)访问设备,效率高. 它是用户空间访问内核空间的一种高效率方式。
mmap – 映射文件到虚拟内存
read,write – copy_to_user 拷贝
对比read write,mmap无需每次都copy_to_user拷贝一次. 它仅需一次映射,以后都直接操作内存buf,效率高。
2. 用共享内存方式,方便进程间通讯,且效率高。
采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。
对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,
而共享内存则只拷贝两次数据:一次从输入文件到共享内存区,另一次从共享内存区到输出文件
mmap原型

  void* mmap (  	void * addr ,   //指定映射的起始地址, 通常设为NULL, 由系统指定 
	                 size_t len ,    //映射到内存的文件长度
	                 int prot ,      //映射区的保护方式, PROT_EXEC: 映射区可被执行 PROT_READ: 可读  PROT_WRITE: 可写
	                 int flags ,     //MAP_SHARED:写入映射区的数据会复制回文件, 且允许其他映射该文件的进程共享。
	                                 //MAP_PRIVATE:对映射区的写入操作会产生一个映射区的复制(copy-on-write), 对此区域所做的修改不会写回原文件。
	                 int fd ,        //由open返回的文件描述符, 代表要映射的文件
	                 off_t offset    //以文件开始处的偏移量, 必须是分页大小的整数倍, 通常为0, 表示从文件头开始映射
)
{//?mmap 怎么用
		//应用
		#include <stdio.h>
		#include<sys/types.h>
		#include<sys/stat.h>
		#include<fcntl.h>
		#include<unistd.h>
		#include<sys/mman.h>
		
		int main()
		{
		 	int fd;
		 	char *start;
		 	//char buf[PAGE_SIZE];
		 	char *buf;
		 
		 	/*打开文件*/
			fd = open("/dev/mydev",O_RDWR);     
			buf = (char *)malloc(PAGE_SIZE);
		 	memset(buf, 0, PAGE_SIZE);
		 	start=mmap(NULL,PAGE_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
		 
		 	/* 读出数据 */
		 	strcpy(buf,start);
		 	sleep (1);
		 	printf("buf 1 = %s\n",buf); 
		 
		
		 	/* 写入数据 */
		 	strcpy(start,"Buf Is Not Null!");     
         
		 	/* 再次读出数据*/
         	memset(buf, 0, PAGE_SIZE);
		 	strcpy(buf,start);
		 	sleep (1);
		 	printf("buf 2 = %s\n",buf);
	
		 	munmap(start,PAGE_SIZE); /*解除映射*/
		 	free(buf);
		 	close(fd); 
		 	return 0; 
		}	
	}

    //驱动:
    char *kbuf = (char *)kmalloc(PAGE_SIZE, GFP_KERNEL);
    
    int myled_mmap(struct file *pf, struct vm_area_struct *vma)
    {
        vma->vm_flags |= VM_IO;//表示对设备IO空间的映射  
        vma->vm_flags |= VM_DONTEXPAND |VM_DONTDUMP;//标志该内存区不能被换出,在设备驱动中虚拟页和物理页的关系应该是长期的,应该保留起来,不能随便被别的虚拟页换出  
        if(remap_pfn_range(vma,//虚拟内存区域,即设备地址将要映射到这里  
                           vma->vm_start,//虚拟空间的起始地址  
                           virt_to_phys(kbuf)>>PAGE_SHIFT,//与物理内存对应的页帧号,物理地址右移12位  
                           vma->vm_end - vma->vm_start,//映射区域大小,一般是页大小的整数倍  
                           vma->vm_page_prot))//保护属性,比如 PAGE_SHARED等  
        {  
            return -EAGAIN;  
        }  
        return 0;  
    }
    
    static struct file_operations myops = {
        .open = myled_open,
        .release = myled_release,
        .mmap = myled_mmap
    };
    
    }
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 C 语言中,`mmap()` 函数用于将一个文件或设备映射到当前进程的地址空间,从而可以通过内存的方式直接访问文件或设备,而不需要通过传统的文件读写 API。`mmap()` 函数的基本用法如下: ```c void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); ``` 其中,各参数的含义如下: - `addr`:期望映射的地址,通常设置为 `NULL`,让内核自动分配; - `length`:要映射的内存区域的大小; - `prot`:映射区域的保护方式,可以是 `PROT_READ`、`PROT_WRITE` 或 `PROT_EXEC` 等; - `flags`:映射区域的标志,可以是 `MAP_SHARED`、`MAP_PRIVATE` 等; - `fd`:要映射的文件描述符; - `offset`:要映射的文件偏移量。 `mmap()` 函数返回映射区域的起始地址,如果映射失败,则返回 `MAP_FAILED`。 下面是一个简单的示例,展示如何将一个文件映射到内存中: ```c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> int main() { int fd; struct stat sb; void *addr; fd = open("test.txt", O_RDONLY); if (fd == -1) { perror("open"); exit(EXIT_FAILURE); } if (fstat(fd, &sb) == -1) { perror("fstat"); exit(EXIT_FAILURE); } addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (addr == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } printf("%s\n", (char *) addr); if (munmap(addr, sb.st_size) == -1) { perror("munmap"); exit(EXIT_FAILURE); } close(fd); return 0; } ``` 在上面的示例中,我们首先使用 `open()` 函数打开一个文件,并使用 `fstat()` 函数获取文件的状态信息。然后,我们使用 `mmap()` 函数将文件映射到内存中,并使用 `printf()` 函数打印出文件的内容。最后,我们使用 `munmap()` 函数释放内存,并关闭文件描述符。 需要注意的是,`mmap()` 函数映射的内存区域不会被自动刷回到文件中,需要手动调用 `msync()` 函数或 `munmap()` 函数来将修改的内容写回到文件中。另外,映射区域的大小必须是内存页面大小的整数倍。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值