范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

一文读懂Linux内存分配策略

  本篇主要以问答的方式来探索Linux内存系统的分配策略Linux 进程的内存分布长什么样?
  在 Linux 操作系统中,虚拟地址空间的内部又被分为 内核空间和用户空间 两部分,不同位数的系统,地址空间的范围也不同。比如最常见的 32 位和 64 位系统,如下所示:
  通过这里可以看出: 32   位系统的内核空间占用 1G  ,位于最高处,剩下的 3G   是用户空间;64   位系统的内核空间和用户空间都是 128T  ,分别占据整个内存空间的最高和最低处,剩下的中间部分是未定义的。
  再来说说,内核空间与用户空间的区别: 进程在用户态时,只能访问用户空间内存;  只有进入内核态后,才可以访问内核空间的内存;
  虽然每个进程都各自有独立的虚拟内存,但是 每个虚拟内存中的内核地址,其实关联的都是相同的物理内存 。这样,进程切换到内核态后,就可以很方便地访问内核空间内存。
  接下来,进一步了解虚拟空间的划分情况,用户空间和内核空间划分的方式是不同的,内核空间的分布情况就不多说了。
  我们看看用户空间分布的情况,以 32 位系统为例,我画了一张图来表示它们的关系:
  通过这张图你可以看到,用户空间内存从 低到高 分别是 6 种不同的内存段:
  程序文件段,包括二进制可执行代码;  已初始化数据段,包括静态常量;  未初始化数据段,包括未初始化的静态变量;  堆段,包括动态分配的内存,从低地址开始向上增长;  文件映射段,包括动态库、共享内存等,从低地址开始向上增长(跟硬件和内核版本有关 );  栈段,包括局部变量和函数调用的上下文等。栈的大小是固定的,一般是   8 MB  。当然系统也提供了参数,以便我们自定义大小;
  在这 6 个内存段中,堆和文件映射段的内存是动态分配的。比如说,使用 C 标准库的  malloc()   或者 mmap()   ,就可以分别在堆和文件映射段动态分配内存。malloc 是如何分配内存的?
  实际上,malloc() 并不是系统调用,而是 C 库里的函数,用于动态分配内存。
  malloc 申请内存的时候,会有两种方式向操作系统申请堆内存。 方式一:通过 brk() 系统调用从堆分配内存  方式二:通过 mmap() 系统调用在文件映射区域分配内存;
  方式一实现的方式很简单,就是通过 brk() 函数将「堆顶」指针向高地址移动,获得新的内存空间。如下图:
  方式二通过 mmap() 系统调用中「私有匿名映射」的方式,在文件映射区分配一块内存,也就是从文件映射区"偷"了一块内存。如下图:
  什么场景下 malloc() 会通过 brk() 分配内存?又是什么场景下通过 mmap() 分配内存?
  malloc() 源码里默认定义了一个阈值: 如果用户分配的内存小于 128 KB,则通过 brk() 申请内存;  如果用户分配的内存大于 128 KB,则通过 mmap() 申请内存;
  注意,不同的 glibc 版本定义的阈值也是不同的。
  malloc() 分配的是物理内存吗?
  不是的, malloc() 分配的是虚拟内存 。
  如果分配后的虚拟内存没有被访问的话,虚拟内存是不会映射到物理内存的,这样就不会占用物理内存了。
  只有在访问已分配的虚拟地址空间的时候,操作系统通过查找页表,发现虚拟内存对应的页没有在物理内存中,就会触发缺页中断,然后操作系统会建立虚拟内存和物理内存之间的映射关系。 malloc(1) 会分配多大的虚拟内存?
  malloc() 在分配内存的时候,并不是老老实实按用户预期申请的字节数来分配内存空间大小,而是 会预分配更大的空间作为内存池 。
  具体会预分配多大的空间,跟 malloc 使用的内存管理器有关系,我们就以 malloc 默认的内存管理器(Ptmalloc2)来分析。
  接下里,我们做个实验,用下面这个代码,通过 malloc 申请 1 字节的内存时,看看操作系统实际分配了多大的内存空间。 #include  #include   int main() {   printf("使用cat /proc/%d/maps查看内存分配 ",getpid());      //申请1字节的内存   void *addr = malloc(1);   printf("此1字节的内存起始地址:%x ", addr);   printf("使用cat /proc/%d/maps查看内存分配 ",getpid());     //将程序阻塞,当输入任意字符时才往下执行   getchar();    //释放内存   free(addr);   printf("释放了1字节的内存,但heap堆并不会释放 ");      getchar();   return 0; }
  执行代码( 先提前说明,我使用的 glibc 库的版本是 2.17 ):
  我们可以通过 /proc//maps 文件查看进程的内存分布情况。我在 maps 文件通过此 1 字节的内存起始地址过滤出了内存地址的范围。 [root@xiaolin ~]# cat /proc/3191/maps | grep d730 00d73000-00d94000 rw-p 00000000 00:00 0                                  [heap]
  这个例子分配的内存小于 128 KB,所以是通过 brk() 系统调用向堆空间申请的内存,因此可以看到最右边有 [heap] 的标识。
  可以看到,堆空间的内存地址范围是 00d73000-00d94000,这个范围大小是 132KB,也就说明了  malloc(1) 实际上预分配 132K 字节的内存 。
  可能有的同学注意到了,程序里打印的内存起始地址是  d73010  ,而 maps 文件显示堆内存空间的起始地址是 d73000  ,为什么会多出来 0x10   (16字节)呢?这个问题,我们先放着,后面会说。
  #  free 释放内存,会归还给操作系统吗?
  我们在上面的进程往下执行,看看通过 free() 函数释放内存后,堆内存还在吗?
  从下图可以看到,通过 free 释放内存后,堆内存还是存在的,并没有归还给操作系统。
  这是因为与其把这 1 字节释放给操作系统,不如先缓存着放进 malloc 的内存池里,当进程再次申请 1 字节的内存时就可以直接复用,这样速度快了很多。
  当然,当进程退出后,操作系统就会回收进程的所有资源。
  上面说的 free 内存后堆内存还存在,是针对 malloc 通过 brk() 方式申请的内存的情况。
  如果 malloc 通过 mmap 方式申请的内存,free 释放内存后就会归归还给操作系统。
  我们做个实验验证下, 通过 malloc 申请 128 KB 字节的内存,来使得 malloc 通过 mmap 方式来分配内存。 #include  #include   int main() {   //申请1字节的内存   void *addr = malloc(128*1024);   printf("此128KB字节的内存起始地址:%x ", addr);   printf("使用cat /proc/%d/maps查看内存分配 ",getpid());    //将程序阻塞,当输入任意字符时才往下执行   getchar();    //释放内存   free(addr);   printf("释放了128KB字节的内存,内存也归还给了操作系统 ");    getchar();   return 0; }
  执行代码:
  查看进程的内存的分布情况,可以发现最右边没有 [head] 标志,说明是通过 mmap 以匿名映射的方式从文件映射区分配的匿名内存。
  然后我们释放掉这个内存看看:
  再次查看该 128 KB 内存的起始地址,可以发现已经不存在了,说明归还给了操作系统。
  对于 「malloc 申请的内存,free 释放内存会归还给操作系统吗?」这个问题,我们可以做个总结了: malloc 通过   brk()   方式申请的内存,free 释放内存的时候, 并不会把内存归还给操作系统,而是缓存在 malloc 的内存池中,待下次使用  ; malloc 通过   mmap()   方式申请的内存,free 释放内存的时候, 会把内存归还给操作系统,内存得到真正的释放  。 为什么不全部使用 mmap 来分配内存?
  因为向操作系统申请内存,是要通过系统调用的,执行系统调用是要进入内核态的,然后在回到用户态,运行态的切换会耗费不少时间。
  所以,申请内存的操作应该避免频繁的系统调用,如果都用 mmap 来分配内存,等于每次都要执行系统调用。
  另外,因为 mmap 分配的内存每次释放的时候,都会归还给操作系统,于是每次 mmap 分配的虚拟地址都是缺页状态的,然后在第一次访问该虚拟地址的时候,就会触发缺页中断。
  也就是说, 频繁通过 mmap 分配的内存话,不仅每次都会发生运行态的切换,还会发生缺页中断(在第一次访问虚拟地址后),这样会导致 CPU 消耗较大 。
  为了改进这两个问题,malloc 通过 brk() 系统调用在堆空间申请内存的时候,由于堆空间是连续的,所以直接预分配更大的内存来作为内存池,当内存释放的时候,就缓存在内存池中。
  等下次在申请内存的时候,就直接从内存池取出对应的内存块就行了,而且可能这个内存块的虚拟地址与物理地址的映射关系还存在,这样不仅减少了系统调用的次数,也减少了缺页中断的次数,这将大大降低 CPU 的消耗 。既然 brk 那么牛逼,为什么不全部使用 brk 来分配?
  前面我们提到通过 brk 从堆空间分配的内存,并不会归还给操作系统,那么我们那考虑这样一个场景。
  如果我们连续申请了 10k,20k,30k 这三片内存,如果 10k 和 20k 这两片释放了,变为了空闲内存空间,如果下次申请的内存小于 30k,那么就可以重用这个空闲内存空间。
  但是如果下次申请的内存大于 30k,没有可用的空闲内存空间,必须向 OS 申请,实际使用内存继续增大。
  因此,随着系统频繁地 malloc 和 free ,尤其对于小块内存,堆内将产生越来越多不可用的碎片,导致"内存泄露"。而这种"泄露"现象使用 valgrind 是无法检测出来的。
  所以,malloc 实现中,充分考虑了 brk 和 mmap 行为上的差异及优缺点,默认分配大块内存 (128KB) 才使用 mmap 分配内存空间。 free() 函数只传入一个内存地址,为什么能知道要释放多大的内存?
  还记得,我前面提到, malloc 返回给用户态的内存起始地址比进程的堆空间起始地址多了 16 字节吗?
  这个多出来的 16 字节就是保存了该内存块的描述信息,比如有该内存块的大小。
  这样当执行 free() 函数时,free 会对传入进来的内存地址向左偏移 16 字节,然后从这个 16 字节的分析出当前的内存块的大小,自然就知道要释放多大的内存了。

自我提升被记录片喂大的孩子有多炸裂(自然篇上)今天我给大家分享高质量的纪录片,每一部都是封神之作!这些纪录片都包含了自然,人文,美学,思维认知等多方面的内容,每一部都值得反复观看。这些纪录片不仅能够让孩子的知识暴涨,还能开拓孩四川龙漕沟突发山洪,伤亡情况8月13日,四川彭州龙漕沟突发山洪,截止今晚7点半,已造成4人死亡,3人重伤,6人轻伤,各方救援力量仍在继续进行搜救。据目击者称,今天15点15分左右,在当地游玩时,突然听到有人尖2022年8月13日那些自然界正在发生的事情专家说,一场灾难性的特大洪水即将降临美国加州,这可能是历史上最昂贵的自然灾害。这是千年难遇的灾难,气候变暖使这种自然灾害变得频繁。2550年就会发生一次。2。研究43个物种的声带,自然(20220811出版)一周论文导读编译李言Nature,11August2022,Volume608Issue7922自然2022年8月11日,第608卷,7922期材料科学MaterialScienceQuant敬畏生命,有爱留在心间想念的时候,就抬头看看天空,无论距离有多远,你们在同一片天空。只要记得云在天上,你们在心上。人,有时候总是被以后该怎么办!给吓退了,其实以后还长,是慢慢过出来的。回头看看,已经在不自我提升被记录片喂大的孩子有多炸裂(自然篇上)今天我给大家分享高质量的纪录片,每一部都是封神之作!这些纪录片都包含了自然,人文,美学,思维认知等多方面的内容,每一部都值得反复观看。这些纪录片不仅能够让孩子的知识暴涨,还能开拓孩新型聚合物可用于去除废水中的染料之后可以重复使用在纺织业和其他行业产生的废水中,染料是主要污染物之一。一种新开发的合成聚合物能够从水中去除这种染料,而且它可以被清理并重新用于处理更多的废水。这种富含氮气不溶于水的聚合物被称为聚碳信通院公布数字政府最新评估结果天翼云通过两项权威评估8月1012日,由中国信息通信研究院(以下简称中国信通院)中国通信标准化协会主办的2022数字化转型发展高峰论坛在北京举办。本次论坛以数字原生产业新生价值共生为主题,现场公布了首届一地17家房企联名请求市政府打击专业房闹及恶意维权每经编辑程鹏,陈梦妤,易启江8月12日,一份名为关于请求维护营商环境增强房企投资信心的纾困解难报告的文件在网络流传,落款处清晰地盖着保利华润绿城龙湖旭辉和葛洲坝等17家品牌房企的印新型聚合物可用于去除废水中的染料之后可以重复使用在纺织业和其他行业产生的废水中,染料是主要污染物之一。一种新开发的合成聚合物能够从水中去除这种染料,而且它可以被清理并重新用于处理更多的废水。这种富含氮气不溶于水的聚合物被称为聚碳信通院公布数字政府最新评估结果天翼云通过两项权威评估8月1012日,由中国信息通信研究院(以下简称中国信通院)中国通信标准化协会主办的2022数字化转型发展高峰论坛在北京举办。本次论坛以数字原生产业新生价值共生为主题,现场公布了首届
不禁要问自己,会喝茶吗?郑板桥在一首诗中有这两句正好清明连谷雨,一杯香茗坐其间。这是距今268年前的清明已过,临近谷雨,郑老先生捧起了一杯香茶,享受着内心的恬静。对照今天,同一个时节,我也一杯香茗坐其间,广西养老金计发基数统一为6184元,当地退休人员的养老金一样吗?广西养老金计发基数统一为6184元,当地退休人员的养老金待遇一样吗?目前全国大多数地方的养老金计发基数实现了统一,这种情况下,当地的退休人员拿到的养老金待遇会不会是一样呢?今天,我一条裙子一万多!王心凌学院穿搭爆红后,这个设计大佬瞒不住了救命,这一周都有谁和居里一样被CyndiBaby无限刷屏?又有多少人的老公被迷得双眼发直,当场出轨?可讲真,当我看到40岁的王心凌重跳爱你时,皒魡青舂借尸还魂了。尤其是这身学院风套早安生活从简单开始,向美好出发太阳早安今天太阳今天是2022年5月30日,星期一,农历五月初一努力生活努力面对每一天的挑战,接受自己保持好心态,一切都会朝着好的方向前进。今日的好事正在晨风里酝酿,只管心怀期待,天天拉足背,轻松九十岁!最简单的长寿方法,在家就能做一位老中医的宝贵养生经验把足背拉一拉,等于拉开4条经络,比经络按摩还有功效,为什么,看完下面的文章就明白了。中医认为,经络决定人体健康,一旦经络出现堵塞,人体就会出现诸多疾病。经络大鼻子变小的修容高光画法,真的很简单这次是人人都能画了。可以把鼻头部分想象成一个球,这个球不仅影响鼻头的宽度,还影响鼻头的高度。想要视觉上缩小鼻头,不仅要画窄,阴影高度也要画低画短,这样鼻头才会显得小巧一些所以笔头的那些年消失在我们视野里的欧洲豪门俱乐部(第二篇)上一回写了一篇那些年消失在我们视野里的欧洲豪门俱乐部,一个比一个惨,唤起了球迷年轻时候的美好回忆。在很多人的强烈建议,以及球迷的留言助攻下,小编决定再加更三篇相关的文章,只不过资料这世界公平吗?穷人为什么穷?从现象看本质,这样解释最通透易懂对于很多工作和生活都不太顺利的人来说,很容易就会产生埋怨情绪,认为世界不公平,或是环境不公正等,但现实真是这样吗?答案是否定的。当然,谁要说世界是绝对公平的,那肯定是在开玩笑。只是行摄西藏川西秘境亚青寺行摄西藏川西秘境亚青寺摄影文字阳光脚步很多人都知道西游记里有一个女儿国在女儿王国里没有男人,繁衍后代都是靠喝湖中的水而受孕历史上是否真的存在这个一个女儿国,这个我们不得而知但是在四当你不开心的时候,请看看这些,你的心就会平静下来人们彼此接近。可以说的只是片面的阳光和一两种世故。可以说的不是最深的孤独。在太阳出来之前,整个世界就像一场梦,只有月亮是真实的。太阳出来后,整个世界都是真实的,只有月亮像一个梦。一CBA三消息篮协换届选举,秦晓雯辟谣离任,广东队热身赛两连胜篮协将换届选举北京时间5月30日,不知不解CBA休赛期已经过去一个月时间,目前各支球队进入到紧张的备战集训当中,中国男篮也是全力备战亚洲杯赛事,本赛季是疫情之下的第三个赛季了,能够