文件空间映射mmap()函数(是什么,为什么,怎么用)

4.文件空间映射mmap()函数

是什么

1、mmap()函数用来将文件或者设备映射到内存中。
2、mmap的特点是按需调页。最开始只申请vma,并不调真正的页。当对某些页进行引用的时候,会引起一个缺页中断,再将页面调入到内存当中,这样避免了对内存的浪费。

为什么要用mmap()函数

mmap的优势: 操作文件就像操作内存一样,适合于对较大文件的读写。

mmap的缺点:
1、文件如果很小,比如60bytes,由于在内存当中的组织都是按页组织的,将文件调入到内存当中是一个页4k,这样其他的4096-60=4036 bytes的内存空间就会浪费掉了。
2、而且文件无法完成拓展,因为mmap到内存的时候,你所能够操作的范围就确定了,无法增加文件的长度。
3、如果系统频繁的使用mmap操作,而且每次mmap的size都不同,那么就会使得内存可能缺少足够的连续的内存空间。

那又怎么了,人家就是用来操作大型数据的。
当mmap的文件是page size的整数倍的时候,使用mmap调用看起来是最合适的,不会造成浪费。
你用其他方式来进行大量数据传递简直不理智。

怎么用

1、开启文件空间映射函数mmap()

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

//以下这点还是要再提一下的,开辟空间的时候要掂量掂量
/*
文件无法完成拓展,因为mmap到内存的时候,你所能够操作的范围就确定了,无法增加文件的长度。
*/

参数释义:
start:用户所要映射的目的地址,一般放NULL,让系统自己去找。
length:顾名思义。
prot:映射区保护方式,取值范围

PROT_EXEC:映射区可执行
PROT_READ:映射区可读取
PROT_WRITE:映射区可写入
PROT_NONE:映射区不可存取

如果要几个功能合在一起,用管道符 | 连通
当然,权限最高的还是映射的文件,如果被映射文件不让读,那就没办法读。

flags:对映射对象的配置

MAP_FIXED:一般不用
MAP_SHARED:共享映射区
MAP_PRIVATE:读时共享,写时复制,对映射区的操作不会对原文件造成影响
MAP_ANONYMOUS:建立匿名映射,不涉及文件,所以用不到fd,也不允许与其他进程共享
MAP_DENYWRITE:对文件的写操作将被禁止,只能通过映射文件对原文件进行操作
MAP_LOCKED:将映射区锁定,不会被虚拟内存重置

shared和private必须且只能选一个。

fd:代表文件的文件描述符。
offset:偏移量。一般设为0,表示从头开始映射。

2、解除映射函数munmap()

//系统调用munmap()

int munmap( void * addr, size_t len )

/*该调用在进程地址空间中解除一个映射关系,addr是调用mmap()时返回的地址,len是映射区的大小。当映射关系解除后,对原来映射地址的访问将导致段错误发生。*/

实例代码:

#include <sys/mman.h>;
#include <sys/types.h>;
#include <fcntl.h>;
#include <unistd.h>;
typedef struct
{
        char name[4];
        int  age;
}people;

main(int argc, char** argv) // map a normal file as shared mem:
{
        int fd,i;
        people *p_map;
        char temp;
        
        fd=open(argv[1],O_CREAT|O_RDWR|O_TRUNC,0777);
        lseek(fd,sizeof(people)*5-1,SEEK_SET);
        write(fd,"",1);
        
        p_map = (people*) mmap( NULL,sizeof(people)*10,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0 );
        close( fd );
        temp = 'a';
		
		//直接使用这种写入方式
        for(i=0; i<10; i++)
        {
                temp += 1;
                memcpy( ( *(p_map+i) ).name, &temp,2 );
                ( *(p_map+i) ).age = 20+i;
        }
        printf(" initialize over /n ");
        sleep(10);

        munmap( p_map, sizeof(people)*10 );
        printf( "umap ok /n" );
}

上一篇:Mmap和valgrind,mmap不会增加堆大小


下一篇:linux c++(mmap)