zoukankan      html  css  js  c++  java
  • malloc中的系统调用brk和mmap

    malloc中的系统调用brk和mmap

    环境
    • ubuntu14.04

    • malloc通过系统调用的方式从操作系统申请内存,malloc内部又通过系统调用brk()mmap来申请内存的。入下图进程虚拟内存布局所示,mmap对应Memory Mapping Segment,brk对应Heap.

    brk

    • brk通过增加program break的位置(brk)从内核申请(非零值初始化)内存。一开始堆段(heap segment)的其实位置(start_brk)和结束位置(brk)指向同一个位置。

      • 当ASLR(Address Space Layout Randomization)关闭时,start_brkbrk同时指向data/bss段的结束位置(end_data)
      • 当ASLR打开时,start_brk和brk同时指向data/bss段的结束位置(end_data)再加上一个随机的brk偏移。
    • 上面的进程虚拟内存布局展示了,start_brk是堆段的开始位置 ,brk(program break)是堆栈的结束位置。

    例子

    /* sbrk, brk 例子 */
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    
    int main()
    {
            void *curr_brk, *tmp_brk = NULL;
    
            printf("Welcome to sbrk example:%d
    ", getpid());
    
            /* sbrk(0) 获取当前 program break 位置 */
            tmp_brk = curr_brk = sbrk(0);
            printf("Program Break Location1:%p
    ", curr_brk);
            getchar();
    
            /* 使用 brk 增加 program break 位置 */
            brk(curr_brk+4096);
    
            curr_brk = sbrk(0);
            printf("Program break Location2:%p
    ", curr_brk);
            getchar();
    
            /* 使用 brk 减小 program break 位置 */
            brk(tmp_brk);
    
            curr_brk = sbrk(0);
            printf("Program Break Location3:%p
    ", curr_brk);
            getchar();
    
            return 0;
    }
    
    • 在增加program break之前,输出如下:

    • start_brk=brk=end_data=0x602000

    • 在增加program break之后,输入如下:

    • start_brk=end_data=0x602000,brk=0x603000.

    • 可以观察到堆段

    00602000-00603000 rw-p 00000000 00:00 0                                  [heap]
    
    • 00602000-00603000是堆段的虚拟地址范围
    • rw-p的标准含义是Read、Write、 NoeXecute、Private
    • 00000000 是文件偏移量,由于没有映射任何文件所以为0
    • 00:00 是major/minor device number,由于没有映射任何文件所以为0
    • 0是inode 也是没有映射任何文件所以为0
    • 【heap】是堆段

    mmap

    • malloc使用mmap创建一个私有匿名的映射段,这个映射段的主要目的是申请一块(零值初始化的)新内存,并且这块内存只能被调用的这个进程独占使用。
    /* 使用mmap系统调用做私有匿名映射的例子 */
    #include <stdio.h>
    #include <sys/mman.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    void static inline errExit(const char* msg)
    {
            printf("%s failed. Exiting the process
    ", msg);
            exit(-1);
    }
    
    int main()
    {
            int ret = -1;
            printf("Welcome to private anonymous mapping example::PID:%d
    ", getpid());
            printf("Before mmap
    ");
            getchar();
            char* addr = NULL;
            addr = mmap(NULL, (size_t)132*1024, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
            if (addr == MAP_FAILED)
                    errExit("mmap");
            printf("After mmap
    ");
            getchar();
    
            /* Unmap mapped region. */
            ret = munmap(addr, (size_t)132*1024);
            if(ret == -1)
                    errExit("munmap");
            printf("After munmap
    ");
            getchar();
            return 0;
    }
    
    • 调用mmap之前:可以看到,属于libc.so和ld-linux.so共享库的内存映射段。

    • 调用mmap之后:如下我们可以看到,mmap映射的内存段已经从上图红色框内分配出去(0xe0000-0xbf000=0x21000).

    • 调用munmap之后,如下输出可以看到mmap已经被解除映射了。

  • 相关阅读:
    在Eclipse/STS里添加代码反编译器(.class)步骤
    关于页面添加字段
    关于jeesite Date和时间戳问题
    关于前端ajax通过实体类向后端传参报不存在问题
    引入字典
    关于添加主键
    简单的前后端分离项目 部署到 centos7
    Cenost7 Mysql5.7 安装 并打开远程访问
    npm install vue-cli -g 报错
    docker 笔记 docker 基础 docker 常用命令
  • 原文地址:https://www.cnblogs.com/binarysystemloophole/p/14849348.html
Copyright © 2011-2022 走看看