用户空间申请内存

当你在编写应用程序时,总是需要很多很多内存去建立你的数据结构,这些内存通常在进程的HEAP区域进行分配。而申请内存的动作通常是通过malloc函数来完成的,相对来说这种方法是简单的,而且是很多教科书上的方法。

今天写这个博客是因为我在实际的工作中遇到很多需要内存分配的测试,我很需要一个类似的eatmem的程序,但是我review很多程序以后,我发现很少有使用malloc来完成分配操作的。一些大牛,都是通过直接调用mmap来分配内存。

mmap一般是高级内存管理的章节才会提及。但是做为程序员应该不会陌生,很多场景会用到这个系统调用。

#include <stdio.h>
#include <stdlib.h>

int main(int argc,char **argv)
{
        char *p;
        p = (char *)malloc(1024*1024);
        *p = 1;
        return 0;
}

这个程序的strace结果如下:

execve("./a.out", ["./a.out"], [/* 62 vars */]) = 0
brk(0)                                  = 0x1459000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6d72b74000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=111211, ...}) = 0
mmap(NULL, 111211, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f6d72b58000
close(3)                                = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\10\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1925280, ...}) = 0
mmap(NULL, 3811872, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f6d725b2000
mprotect(0x7f6d7274c000, 2093056, PROT_NONE) = 0
mmap(0x7f6d7294b000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x199000) = 0x7f6d7294b000
mmap(0x7f6d72951000, 14880, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f6d72951000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6d72b57000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6d72b56000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6d72b55000
arch_prctl(ARCH_SET_FS, 0x7f6d72b56700) = 0
mprotect(0x7f6d7294b000, 16384, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ)     = 0
mprotect(0x7f6d72b75000, 4096, PROT_READ) = 0
munmap(0x7f6d72b58000, 111211)          = 0
mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f6d72a54000
exit_group(0)                           = ?
+++ exited with 0 +++

其中最后一个mmap函数对应于示例代码中的malloc函数。
这说明malloc函数就是利用mmap系统调用进行内存分配的。

mmap函数原型:

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

参数比较多,
- addr,期望的内存使用地址。往往写成NULL 或者是0,以便让kernel来决定申请的内存座落在哪里。kernel分配内存会考虑页面对齐问题。
- length,申请内存的数量。
- prot,内存保护模式选择,读、写、执行模式。
- PROT_EXEC 页面可以执行代码;可以理解为如果RIP指向这个区域,会执行里面的代码。
- PROT_READ 页面可以执行读操作;
- PROT_WRITE 页面可以执行写操作;
- PROT_NONE 页面不能被访问;
- flags,这个参数主要是配置所申请内存页面的某些属性以及kernel处理他们时的某些特殊行为。
- MAP_SHARED,这个是共享内存页,其他进程映射相同文件时可以看到本进程的修改内容,而且所修改的内容会被写回到文件中。通过msync可以精确地控制写回动作。
- MAP_PRIVATE,这个标记用于创建一个写时拷贝页面,在页面中的修改动作不会同步到真实的文件中。没有明确地说明,在文件被映射期间,如果文件内容发生变化,映射区内容是否会同步变化。
- 另有其他一些Flag标记,内容如下:
- MAP_32BIT,将映射页面定位在2G地址空间以内,为了提高性能。早期64位处理器需要这个。
- MAP_ANONYMOUS,这个标记很特殊,十分常用,用于建立一个不需要文件支持的内存映射。生成的页面内容被初始化成0。后面两个参数会被忽略,但是为了移植性的考虑,降-1传个fd参数是明智的。
- MAP_FIXED,这个参数意味传入的申请内存的地址,是固定的,不可变的,如果不能做到,函数将失败返回。
- MAP_GROWSDOWN,从高端地址向低端地址延伸。使用Stack区进行分配。
- MAP_HUGETLB,使用’huge pages’,进行分配。
- MAP_HUGE_2MB,它与MAP_HUGTLB连用,用于选择huge page的size。
- MAP_HUGE_1GB,它与MAP_HUGTLB连用,用于选择huge page的size。
- MAP_LOCKED,锁定内存,于mlock类似。防止该内存页面换出(swap-out)。
- MAP_UNINITIALIZED,不初始化页面。这个选项需要内核开启CONFIG_MMAP_ALLOW_UNINITIALIZED选项。
这里还有一些标志没有罗列,详情可以参考man手册。
- fd,文件描述符。
- offset,偏移量。

由于今天聊的是内存,所以fd,offset就可以忽略了。

在使用mmap进行内存分配时,使用一下函数代码:

mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)

申请位置不确定,申请的size是4096,可读/可写,私有/不映射任何文件。

char *p
 p = mmap(0, 4, PROT_WRITE|PROT_READ, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
 if (p == MAP_FAILED) {                                                
         exit(-1);                                                     
 }                                                                     
 *p = 104;                                                             
 printf("%d\n", *p);                                                   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值