ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

malloc和free,brk和sbrk和mmap和munmap的使用和关系以及内存分配的原理

2021-11-17 16:02:55  阅读:202  来源: 互联网

标签:MAP malloc 映射 sbrk mmap brk 内存


目录

一.使用

        1.1 malloc和free

        2.brk和sbrk

        2.1 sbrk

        2.2 brk

         3. mmap/munmap

二.关系

三.内存分配原理

 四.malloc底层


一.使用

        1.1 malloc和free

参数:申请内存大小

返回值:成功返回申请空间起始指针,失败返回空。

  1 #include <stdio.h>  
  2 #include <stdlib.h>
  3 
  4 int main(){
  5 
  6   char *str = (char *)malloc(10);
  7   if(str == NULL){
  8     perror("malloc fail");
  9   }
 10   int *ptr = (int *)malloc(10*sizeof(int));
 11   if(ptr == NULL){
 12     perror("malloc fail");
 13   }
 14   
 15                                                                                                                                                          
 16                                                                                                                                               
 17   free(str);                                                                                                                                  
 18   //防止野指针                                                                                                                                
 19   str = NULL;                           
 20   free(ptr);                            
 21   ptr = NULL                               
 22   return 0;                             
 23 } 

        第一次调用malloc系统会分配33页(一页等于4kb)的空间。之后再申请空间会从33页空间剩余的空间中申请。

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 int main(){
  5 
  6   char *str = (char *)malloc(1);
  7   if(str == NULL){
  8     perror("malloc fail");
  9   }
 10   //只申请了1字节空间,但是这样遍历不会报错
 11   for(int i=0; i<32*4096; i++){                                                                                                                          
 12     str[i] = 'a';
 13   }
 14 
 15   return 0;
 16 }

结果没有报错: 

 将代码改一下:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 int main(){
  5 
  6   char *str = (char *)malloc(1);
  7   if(str == NULL){
  8     perror("malloc fail");
  9   }
 10   //只申请了1字节空间,申请超过33页                                                                                                                      
 11   for(int i=0; i<33*4096; i++){           
 12     str[i] = 'a';                         
 13   }
 14 
 15   return 0;
 16 }

 结果报错:

         当你申请大小为n的内存时,起始系统给你的空间会大于你申请的空间数,一般后面会有12字节的控制信息。这个控制信息一般不可以修改。

        2.brk和sbrk

        brk和sbrk底层维护了一个堆上的指针,以增量的方式管理动态内存(堆)。

        2.1 sbrk

 参数:申请空间大小,0不申请空间,大于0申请空间,小于0 释放空间

返回值:申请内存空间的起始地址,失败返回-1。

来一段代码说明一下:

        2.2 brk

 参数:需要将堆顶指针向后移动到哪个地址。移动的空间大小,就是申请的空间大小。

返回值:失败返回-1,成功放回0。

         3. mmap/munmap

mmap参数:

start:映射区的开始地址

length:映射区的长度

prot:期望的内存保护标志,不能与文件的打开模式冲突。是以下的某个值,可以通过or运算合理地组合在一起

1 PROT_EXEC :页内容可以被执行
2 PROT_READ :页内容可以被读取
3 PROT_WRITE :页可以被写入
4 PROT_NONE :页不可访问

flags:指定映射对象的类型,映射选项和映射页是否可以共享。它的值可以是一个或者多个以下位的组合体

 1 MAP_FIXED //使用指定的映射起始地址,如果由start和len参数指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。如果指定的起始地址不可用,操作将会失败。并且起始地址必须落在页的边界上。
 2 MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新。
 3 MAP_PRIVATE //建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。
 4 MAP_DENYWRITE //这个标志被忽略。
 5 MAP_EXECUTABLE //同上
 6 MAP_NORESERVE //不要为这个映射保留交换空间。当交换空间被保留,对映射区修改的可能会得到保证。当交换空间不被保留,同时内存不足,对映射区的修改会引起段违例信号。
 7 MAP_LOCKED //锁定映射区的页面,从而防止页面被交换出内存。
 8 MAP_GROWSDOWN //用于堆栈,告诉内核VM系统,映射区可以向下扩展。
 9 MAP_ANONYMOUS //匿名映射,映射区不与任何文件关联。
10 MAP_ANON //MAP_ANONYMOUS的别称,不再被使用。
11 MAP_FILE //兼容标志,被忽略。
12 MAP_32BIT //将映射区放在进程地址空间的低2GB,MAP_FIXED指定时会被忽略。当前这个标志只在x86-64平台上得到支持。
13 MAP_POPULATE //为文件映射通过预读的方式准备好页表。随后对映射区的访问不会被页违例阻塞。
14 MAP_NONBLOCK //仅和MAP_POPULATE一起使用时才有意义。不执行预读,只为已存在于内存中的页面建立页表入口。

fd:有效的文件描述词。如果MAP_ANONYMOUS被设定,为了兼容问题,其值应为-1

offset:被映射对象内容的起点

mmap返回值:

        成功返回指向该空间的起始地址,失败MAP_FAILED (that is, (void *) -1)被返回。

mmap作用:

        在文件映射区开辟一个大小为length的空间。

munmap参数:

        addr是调用mmap()时返回的地址,

        len是映射区的大小

munmap返回值:

        成功执行时,munmap()返回0。失败时,munmap返回-1。

munmap作用:

        该调用在进程地址空间中解除一个映射关系,即释放空间

 操作文件:

二.关系

        malloc的底层调用的是是brk和mmap来申请内存。对应free用的是brk和munmap释放内存。

三.内存分配原理

        从操作系统的角度来看,进程分配内存有两种方式,分别由两个系统调用完成:brk和mmap(不考虑共享内存)。

  • brk:将数据段最高地址往进程地址空间的高地址方向移动。
  • mmap:在文件映射区申请一个空闲内存。

        这两种方式分配的都是虚拟内存,没有分配物理内存在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系。

分配内存时有两种情况:

情况一:申请的内存小于128KB,申请内存是将堆顶指针向高地址方向移动,不会作初始化。

情况二:大于128k的内存,使用mmap分配内存,在堆和栈之间找一块空闲内存分配(对应独立内存,而且初始化为0)。

        默认情况下,malloc函数分配内存,如果请求内存大于128K(可由M_MMAP_THRESHOLD选项调节),那就不是去推堆顶指针了,而是利用mmap系统调用,从堆和栈的中间分配一块虚拟内存。

        原因:brk是以增量的形式申请空间的,brk分配的内存需要等到高地址内存释放以后才能释放。而mmap申请的内存可以单独释放。

 有一种情况:

       当最高地址空间的空闲内存超过128K(可由M_TRIM_THRESHOLD选项调节)时,执行内存紧缩操作(trim)。如下图。

        既然堆内内存brk和sbrk不能直接释放,为什么不全部使用 mmap 来分配,munmap直接释放呢? 

        首先brk释放的空间,并不一定真正释放了。如果没有释放可以被重复利用。而mmap申请的空间,直接调用munmap是将空间真正释放了。

        首先申请空间需要用用户态进入内核态,需要成本。而频繁调用mmap有用户态变为内核态的频率肯定会比用brk高。即CPU消耗会很高。

         在glibc 的 malloc 实现中,充分考虑了 sbrk 和 mmap 行为上的差异及优缺点,默认分配大块内存 (128k) 才使用 mmap 获得地址空间,也可通mallopt(M_MMAP_THRESHOLD, <SIZE>) 来修改这个临界值。

借鉴:Linux内存分配小结--malloc、brk、mmap_gfgdsg的专栏-CSDN博客

 四.malloc底层

        malloc底层管理的是一个链表数组,类似于哈希桶的结构。哈希桶的位置,映射的是内存块的大小。一般这个内存块的大小不会正好一字节一字节的增长,而是会设置一个对齐数,桶位置表示的内存块的大小绘制这个对齐数的整数倍。比如,对齐数为8字节,哈希桶的第一个位置连接的内存块都是8字节大小的内存块,第二个桶连接的都是16字节大小的内存,一次类推。

        当用户malloc申请内存,通过用户申请的内存大小,通过算法,找到对应的桶的位置。如果桶下有内存块,将该内存块从哈希桶中弹出,然后返回该内存块的起始地址给用户。如果当前桶没有内存块,会向桶后找大的内存块,如果有内存块,会将内存块切割成两个内存块,间用户需要的内存块的起始地址返回给用户,将另外一个内存块连接到对应桶内。如果桶后也没有大的内存块,就会向系统申请一个较大的内存块,进行切割,返回用户需要的,新的连接到对应哈希桶位置。

        用户free释放内存块并不是直接还给了系统,而是还给了哈希桶。如果有其它内存块和释放的内存块相邻,底层会将相邻的内存块合并,再连接到哈希桶对应位置。

上面是我自己简单总结,如有不足,希望大佬们可以帮忙指出,谢谢。

详细可以看malloc 底层实现

标签:MAP,malloc,映射,sbrk,mmap,brk,内存
来源: https://blog.csdn.net/weixin_57023347/article/details/121291573

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有