mmap和munmap函数

本文详细介绍了mmap和munmap这两个系统调用的功能及使用方法。mmap用于将文件或者设备映射到进程的内存空间,提高了数据访问效率;munmap则用于取消这种映射。文章还给出了一个具体的mmap应用实例。

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

原:http://blog.sina.com.cn/s/blog_605f5b4f0100znqs.html

 

 

mmap munmap是一对操作命令,就像mallocfree命令一样


Mmap and munmap: map or unmap files or devices into memory(操作的内存页Page)


mmap操作提供了一种机制,让用户程序直接访问设备内存,这种机制,相比较在用户空间和内核空间互相拷贝数据,效率更高。在要求高性能的应用中比较常用。mmap映射内存必须是页面大小的整数倍,面向流的设备不能进行mmapmmap的实现和硬件有关。


munmap执行相反的操作,删除特定地址区域的对象映射,基于文件的映射,在mmapmunmap执行过程的任何时刻,被映射文件的st_atime可能被更新。如果st_atime字段在前述的情况下没有得到更新,首次对映射区的第一个页索引时会更新该字段的值。用PROT_WRITE 和 MAP_SHARED标志建立起来的文件映射其st_ctime 和 st_mtime,在对映射区写入之后但在msync()通过MS_SYNC 和 MS_ASYNC两个标志调用之前会被更新


#include <sys/mman.h>


void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);


int munmap(void *addr, size_t length);


 

mmap() creates new mapping in the virtual address space of the calling process.  The starting address for the new mapping is specified in addr Thlength argument specifies the length of the mapping.


If addr is NULL, then the kernel chooses the address at which to create the       mapping; this is the most portable method of creating new mapping.  If addr is not NULL, then the kernel takes it as hint about where to place the mapping; on Linux, the mapping will be created at nearby page boundary.  The address of the new mapping is returned as the result of the call.


The contents of file mapping (as opposed to an anonymous mapping; see MAP_ANONYMOUS below), are initialized using length bytes starting at offset  offset in the file (or other object) referred to by the file descriptor fd.

       

offset must be multiple of the page size as returned by sysconf(_SC_PAGE_SIZE).


The prot argument describes the desired memory protection of the mapping (and      must not conflict with the open mode of the file).  It is either PROT_NONE or the bitwise OR of one or more of the following flags:

PROT_EXEC  Pages may be executed.       

PROT_READ  Pages may be read.       

PROT_WRITE Pages may be written.     

 PROT_NONE  Pages may not be accessed.


The flags argument determines whether updates to the mapping are visible to other processes mapping the same region, and whether updates are carried through to the underlying file. This behavior is determined by including exactly one of the following values in flags:

MAP_SHARED Share this mapping.  

Updates to the mapping are visible to otherprocesses that map this fileand are carried through to the underlying file.  The file may not actually be updated until msync(2) or munmap() is called.


MAP_PRIVATE   Create private copy-on-Write mapping. Updates to the mapping are not visible to other processes mapping the same file, and are not carried through to the underlying file.  It is unspecified whether changes made to the file after the mmap() call are visible in the mapped region.


In addition, zero or more of the following values can be ORed in flags:


MAP_ANONYMOUS

The mapping is not backed by any file; its contents are initialized to zero. The fd and offset arguments are ignored; however, some implementations require fd to be -1 if MAP_ANONYMOUS (or MAP_ANONis specified, and portable applications should ensure this.  The use of MAP_ANONYMOUS in conjunction with MAP_SHARED is only supported on Linux since kernel 2.4.


MAP_FIXED

Don't interpret addr as hint: place the mapping at exactly that address.  addr must be multiple of the page size. If the memory region specified by addr and len overlaps pages of any existing mapping(s), then the overlapped part of the existing mapping(s) will be discarded. If the specified address cannot be used, mmap() will fail. Because requiring fixed address for mapping is less portable, the use of this option is discouraged.


MAP_HUGETLB (since Linux 2.6.32)

Allocate the mapping using "huge pages."  See the kernel source file Documentation/vm/hugetlbpage.txt  for further information.


MAP_NORESERVE

Do not reserve swap space for this mapping.  When swap space is reserved, one has the guarantee that it is possible to modify the mapping.  When swap space is not reserved one might get SIGSEGV upon a write if no physical memory is available. See also the discussion of the file /proc/sys/vm/overcommit_memory in proc(5)In kernels before2.6, this flag only had effect for private writable mappings.


MAP_POPULATE (since Linux 2.5.46)

Populate (prefault) page tables for mapping. For file mapping, this causes read-ahead on the file.  Later accesses to the mapping will not be blocked by page faults.  MAP_POPULATE is only supported for private mappings since Linux 2.6.23.


 

Memory mapped by mmap() is preserved across fork(2)with the same attributes.(猜想一定和进程创建fork的Copy On Write机制 有关联,说不定使用的就是MAP_PRIVATE



 file is mapped in multiples of the page size.  For file that is not a multiple of the page size, the remaining memory is zeroed when mapped, and writes to that region are not written out to the file. The effect of changing the size of the underlying file of mapping on the pages that correspond to added or removed regions of the file is unspecified.


Munmap()       

The munmap() system call deletes the mappings for the specified address range,      and causes further references to addresses within the range to generate invalid memory references. The region is also automatically unmapped when the process is terminated.  On the other hand, closing the file descriptor does not unmap the region.


The address addr must be multiple of the page size.  All pages containing a part of the indicated range are unmapped, and subsequent references to these pages will generate SIGSEGV It is not an error if the indicated range does not contain any mapped pages.


EXAMPLE:

The following program prints part of the file specified in its first command-line argument to standard output. The range of bytes to be printed is specified via offset and length values in the second and third command-line arguments.  The program creates memory mapping of the required pages of the file and then uses write(2) to output the desired bytes.

       #include <sys/mman.h>

       #include <sys/stat.h>

       #include <fcntl.h>

       #include <stdio.h>

       #include <stdlib.h>

       #include <unistd.h>

       #define handle_error(msg) \

           do perror(msg); exit(EXIT_FAILURE); while (0)

       int  main(int argc, char *argv[])

       {

           char *addr;

           int fd;

           struct stat sb;

           off_t offset, pa_offset;

           size_t length;

           ssize_t s;

           if (argc || argc 4) {

               fprintf(stderr, "%s file offset [length]\n", argv[0]);

               exit(EXIT_FAILURE);

           }

           fd open(argv[1], O_RDONLY);//第二个参数为文件名

           if (fd == -1)

               handle_error("open");

           if (fstat(fd, &sb) == -1)           

               handle_error("fstat");

          offset atoi(argv[2]);//第三个参数为偏移量 atoi将一个字符串变成一个int

           pa_offset offset ~(sysconf(_SC_PAGE_SIZE) 1);

               

 

           if (offset >= sb.st_size) {

               fprintf(stderr, "offset is past end of file\n");

               exit(EXIT_FAILURE);

           }

           if (argc == 4) {

               length atoi(argv[3]);//第四个参数时映射内存大小

               if (offset length sb.st_size)

                   length sb.st_size offset;

                       

           else    

               length sb.st_size offset;

           }

           addr mmap(NULL, length offset pa_offset, PROT_READ,

                       MAP_PRIVATEfd, pa_offset);

           if (addr == MAP_FAILED)

               handle_error("mmap");

          write(STDOUT_FILENO, addr offset pa_offset, length);

           if (s != length) {

               if (s == -1)

                   handle_error("write");

               fprintf(stderr, "partial write");

               exit(EXIT_FAILURE);

           }

           exit(EXIT_SUCCESS);

       }

 

<think>嗯,用户想了解munmap函数的使用说明、示例代码、报错处理以及相关的Linux内存管理知识。首先,我需要回顾一下munmap的基本用法。munmap用于释放由mmap创建的内存映射,这个函数在解除映射时可能会遇到一些错误,比如无效的地址或长度,或者权限问题。用户可能需要具体的示例代码来理解如何正确使用它,以及如何处理常见的错误情况。 接下来,我应该检查用户提供的引用内容,看看是否有相关的信息可以支持回答。引用[1]提到了mmap函数用于内存映射文件映射,而munmap自然是与之对应的解除映射的函数。引用[3]提到gdb调试工具,可能在处理报错时可以用到。引用[4]关于内存存储的部分可能不直接相关,但需要确认是否有其他相关信息。 用户可能需要知道munmap的参数,比如addrlength的正确使用方法。示例代码部分最好用C语言展示,因为mmap/munmap是系统调用,通常在C中使用。同时,报错处理需要解释常见的错误码,如EINVAL、EACCES等,并给出解决方法,比如检查地址对齐或长度是否正确。 另外,用户提到“Linux内存管理”,可能需要补充munmap在内存管理中的作用,比如如何与brk、mmap协同工作。引用[1]中提到了brkmmap,可以指出munmap用于释放mmap分配的内存,而brk释放则需要通过调整堆指针,但munmap不处理brk分配的内存。 还需要考虑用户可能遇到的问题,比如内存泄漏、悬垂指针等,这些在示例代码中需要提醒。例如,在munmap之后,原来的指针应该设置为NULL,避免误用。同时,权限问题可能导致munmap失败,比如映射区域是只读的,但尝试用munmap解除映射,这时候可能需要检查之前的mmap参数。 最后,生成的相关问题需要围绕用户可能进一步想知道的内容,比如mmap的其他用法,内存管理机制,或者调试工具的使用,这样可以引导用户深入了解更多相关知识。</think>### munmap函数使用说明 #### 一、基本功能 munmap是Linux系统中用于解除内存映射的系统调用,主要处理由$mmap()$创建的映射区域[^1]。其函数原型为: $$int\ munmap(void\ *addr,\ size_t\ length);$$ 关键参数说明: - $addr$:必须是内存页对齐地址(通常由$mmap$返回) - $length$:必须是页大小的整数倍 #### 二、使用示例 ```c #include <sys/mman.h> #include <stdio.h> int main() { size_t size = 4096; // 1页大小 void *addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if(addr == MAP_FAILED) { perror("mmap failed"); return -1; } // 使用映射内存... if(munmap(addr, size) == -1) { perror("munmap failed"); return -1; } return 0; } ``` #### 三、常见报错处理 | 错误码 | 原因 | 解决方案 | |--------|------|----------| | EINVAL | 地址未页对齐/长度包含无效值 | 确保addr是$mmap$返回值,长度是页大小的整数倍 | | ENOMEM | 指定范围包含非法地址 | 使用/proc/self/maps验证映射范围 | | EACCES | 权限不匹配(如尝试写只读区域) | 检查$mmap$时的PROT参数设置 | #### 四、内存管理要点 1. 必须精确匹配$mmap$时的地址长度参数 2. 映射解除后立即失效,继续访问会导致段错误 3. 匿名映射内存会被系统自动回收,文件映射会触发写回操作 4. 与brk分配的内存在管理方式上存在本质差异 #### 五、调试建议 1. 使用$strace$跟踪系统调用 2. 通过/proc/pid/maps查看内存映射状态 3. 结合gdb定位段错误地址[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值