C/C++ 使用mmap/munmap函数分配内存

在C/C++ 中常用的内存分配和管理的方式有很多,如智能指针, STL容器, new/delete, malloc/free, brk, sbrk等等,最近研究了一下Unix比较底层的一种内存管理方式mmap/munmap,需要完全自己来维护分配的虚拟内存,没有任何其他辅助的数据结构来帮助维护内存空间。

一、在终端里输入 man mmap 可以查看此函数的API文档,此函数的具体描述如下:

void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);

具体参数含义

start :  指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址。

length:  代表将文件中多大的部分映射到内存。

prot  :  映射区域的保护方式。可以为以下几种方式的组合:

PROT_EXEC 映射区域可被执行

PROT_READ 映射区域可被读取

PROT_WRITE 映射区域可被写入

PROT_NONE 映射区域不能存取

flags :  影响映射区域的各种特性。在调用mmap()时必须要指定MAP_SHARED 或MAP_PRIVATE。

MAP_FIXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。

MAP_SHARED 对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。

MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write)对此区域作的任何修改都不会写回原来的文件内容。

MAP_ANONYMOUS建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。

MAP_DENYWRITE只允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。

MAP_LOCKED 将映射区域锁定住,这表示该区域不会被置换(swap)。

fd    :  要映射到内存中的文件描述符。如果使用匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。有些系统不支持匿名内存映射,则可以使用fopen打开/dev/zero文件,

然后对该文件进行映射,可以同样达到匿名内存映射的效果。

offset:文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是PAGE_SIZE的整数倍。

返回值:

若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1),错误原因存于errno 中。

错误代码:

EBADF  参数fd 不是有效的文件描述词

EACCES 存取权限有误。如果是MAP_PRIVATE 情况下文件必须可读,使用MAP_SHARED则要有PROT_WRITE以及该文件要能写入。

EINVAL 参数start、length 或offset有一个不合法。

EAGAIN 文件被锁住,或是有太多内存被锁住。

ENOMEM 内存不足。

用户层的调用很简单,其具体功能就是直接将物理内存直接映射到用户虚拟内存,使用户空间可以直接对物理空间操作。但是对于内核层而言,其具体实现比较复杂。

二、例子程序如下

//
//  main.cpp
//
//
//  Created by ChengChao on 14-9-27.
//  Copyright (c) 2014年 cc. All rights reserved.
//

#include <iostream>
#include <sys/mman.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

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

    //申请内存
    int* arr = static_cast<int*>(mmap(
                    NULL,                   //分配的首地址
                    getpagesize(),          //分配内存大小(必须是页的整数倍, 32位1页=4k)
                    PROT_READ | PROT_WRITE, //映射区域保护权限:读|写
                    MAP_ANON | MAP_SHARED,  //匿名映射(不涉及文件io), 后面两个参数忽略
                    0,                      //要映射到内存中的文件描述符
                    0                       //文件映射的偏移量,通常设置为0,必须是页的整数倍
                ));
    printf("申请内存大小=%dk\n", sizeof(arr));

    *arr = 10;
    *(arr + 1) = 20;
    *(arr + 2) = 30;

    printf("arr[2]=%d\n", arr[2]);

    //释放指针arr指向的内存区域,并制定释放的内存大小
    munmap(arr, getpagesize());

    return 0;
}

我是在64位的Mac OS X系统下编译运行的,64位系统内存页的大小为8k, 32位为4k

时间: 2024-11-07 13:30:31

C/C++ 使用mmap/munmap函数分配内存的相关文章

malloc函数分配内存失败的常见原因

malloc()函数分配内存失败的常见原因:  1. 内存不足.  2. 在前面的程序中出现了内存的越界访问,导致malloc()分配函数所涉及的一些信息被破坏.下次再使用malloc()函数申请内存就会失败,返回空指针NULL(0). malloc中做了哪些事情: 简单的说就是系统中有一个位置标记,标记了 当前已经用掉的内存用到了什么位置,系统中还有一个链表把各个未用的内存块连接起来,申请新内存的时候就未分配的链表中依次查找一个够用的内存块,把这次分配的内存地址返回给用户,把这次用掉的进行映射

内存分配原理 -进程分配内存的两种方式,分别有系统调用完成brk() 和mmap()(不设计共享内存)

如何查看进程发生缺页中断的次数? 用ps -o majflt,minflt -C program命令查看. majflt代表major fault,中文名叫大错误,minflt代表minor fault,中文名叫小错误.           这两个数值表示一个进程自启动以来所发生的缺页中断的次数. 发成缺页中断后,执行了那些操作? 当一个进程发生缺页中断的时候,进程会陷入内核态,执行以下操作: 1.检查要访问的虚拟地址是否合法 2.查找/分配一个物理页 3.填充物理页内容(读取磁盘,或者直接置0

分配内存(Linux设备驱动程序)

分配内存 介绍设备驱动程序中使用内存的方法: 如何最好地利用系统内存资源. kmalloc函数 kmalloc内存分配引擎是一个功能强大的工具. #include <linux/slab.h> void *kmalloc(size_t size, int flags); 参数分配表示flags能够以多种方式控制kmalloc的行为. 标志GFP_KERNEL表示内存分配是代表运行在内核空间的进程执行的,这意味着调用它的函数正代表 某个进程执行系统调用. 使用GFP_KERNEL允许kmallo

内存控制篇calloc free getpagesize malloc mmap munmap

calloc(配置内存空间) 相关函数 malloc,free,realloc,brk 表头文件 #include <stdlib.h> 定义函数 void *calloc(size_t nmemb,size_t size); 函数说明 calloc()用来配置nmemb个相邻的内存单位,每一单位的大小为size,并返回指向第一个元素的指针.这和使用下列的方式效果相同:malloc(nmemb*size);不过,在利用calloc()配置内存时会将内存内容初始化为0. 返回值 若配置成功则返回

Delphi 的内存操作函数(1): 给字符指针分配内存

马上能想到的函数有: GetMem AllocMem ReallocMem FreeMem GetMemory ReallocMemory FreeMemory New Dispose NewStr DisposeStr StrNew StrAlloc StrDispose GlobalAllocPtr GlobalFreePtr WideStrAlloc AnsiStrAlloc StrDispose Move MoveMemory CopyMemory ZeroMemory FillMemo

Delphi 的内存操作函数(2): 给数组指针分配内存

静态数组, 在声明时就分配好内存了, 譬如: var   arr1: array[0..255] of Char;   arr2: array[0..255] of Integer; begin   ShowMessageFmt('数组大小分别是: %d.%d', [SizeOf(arr1), SizeOf(arr2)]);   {数组大小分别是: 512.1024} end; 对静态数组指针, 虽然在声明之处并没有分配内存, 但这个指针应该分配多少内存是有定数的. 这种情况, 我们应该用 Ne

Delphi 的内存操作函数(1): 给字符指针分配内存( 给字符指针(PChar、PWideChar、PAnsiChar)分配内存最佳的选择是StrAlloc。分配内存的时候会对字符串进行初始化)

马上能想到的函数有: GetMem AllocMem ReallocMem FreeMem GetMemory ReallocMemory FreeMemory New Dispose NewStr DisposeStr StrNew StrAlloc StrDispose GlobalAllocPtr GlobalFreePtr WideStrAlloc AnsiStrAlloc StrDispose Move MoveMemory CopyMemory ZeroMemory FillMemo

通过指针子函数中分配内存,在主函数中实现赋值

实现了在子函数中分配内存,在主函数中实现赋值或对其值的修改. 原文地址:https://www.cnblogs.com/jefy/p/9383899.html

c malloc分配内存

php中的内存分配有用类似emalloc这样的函数,emalloc实际上是C语言中的malloc的一层封装,php启动后,会向OS申请一块内存,可以理解为内存池,以后的php分配内存都是在这块内存池中进行的,以至于efree,也不会向OS退回内存,而只是设置标志位,标识efree这块内存不再使用了,这样做的好处是,速度快,避免系统调用,因为频繁的从用户态和内核态之间的切换是很费CPU的. C语言的malloc函数的后面是glibc(内存管理系统) , 前段时间在看到php内存分配时,看到了ema