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

一文读懂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 字节的分析出当前的内存块的大小,自然就知道要释放多大的内存了。

鸣枪致敬全国哀悼日澳洲将如何纪念女王离世澳联邦议会暂停工作全澳哀悼女王伊丽莎白二世的逝世,澳洲各地下半旗,联邦议会暂停工作。SBS中文网报道,澳洲人在周五早上醒来时,听到了女王在苏格兰的巴尔莫勒尔(Balmoral)平静阿盟通过涉华决议,主要内容有三点,包括支持一中,中方回应据中国外交部网站消息,日前在阿拉伯国家联盟举行的外长理事会会议上,通过了阿拉伯中国关系决议,对此中方在回应是给出了极高的评价,表示高度赞赏。这份决议最主要的内容有三点第一,阿盟外长BMWX2追逐时间创新登场每一秒都是尽兴创新技术和应用,绿色环保可持续。创新BMWX2反其道而型天生型动派不羁型格,独创大胆风格。创新BMWX2融合大胆叛逆的M基因,黑色高光饰件勾勒中央进气口的底部轮廓,塑造运动主义独有再添2所外语特色学校,广州黄埔广外教育集团授牌成立南都讯黄埔区再添2所外语特色学校。9月9日,广州黄埔区教育局与广东外语外贸大学合作办学签约暨黄埔广外教育集团授牌活动举办,广东外语外贸大学附属科学城实验学校和广东外语外贸大学附属黄中风瘫痪吞药自杀,这6位老演员有儿有女,晚年却无人养老娱乐圈中不少老演员,年轻时风光无限,在各自领域取得了不错的成绩。但他们到了老年后却被儿女弃养不管不顾,真可谓是晚景凄凉。1夏萍夏萍被誉为TVB金牌奶奶,她在影视圈已经摸爬滚打60余海南扎实推进放心消费创建活动已培育751家线下购物无理由退货承诺单位今年以来,海南各级市场监管部门围绕安全质量价格服务维权五个放心目标,着力打通制约消费潜力释放的堵点,取得积极成效。截至8月底,全省累计创建385家放心消费单位23个放心消费商圈,培放弃50万年薪,网红教授陈春花又辞职,这次是中国银行!此前已从北大辞职从北大辞职后,网红教授陈春花又辞去一家银行的独董职务。8月30日,中国银行(SH601988,股价3。03元股,市值8920亿元)发布公告称,因个人工作原因,陈春花女士辞去该行独立流行了好几年的阔腿裤,学日本主妇穿大一号更时髦,高级显瘦有那么一件裤装,一直都备受女性的青睐和追捧,它就是阔腿裤!作为一款流行已久的时尚单品,阔腿裤在时尚界当中的地位还是非常稳定的,毕竟它遮肉显瘦显高的优势还是不容小觑的。但是在今年秋天钟意高级文案1。你还有明亮的未来呢2。虽然您已偏航但您仍在最优路线上3。自己满溢自己降露自己做焦枯荒野上的雨4。行色匆匆的时代里诉苦是无用的5。别天真的以为自己会是风流浪子的最后一站6。要敢爱中秋节文案愿世间所有的团圆,都不必跋山涉水相见1。好时节,愿得年年,常见中秋月。2。月光所照皆是故乡,双脚所踏皆是生活。3。我想请你赏月,时间不一样没关系,地点不一样也没关系。4。皓月当空,惟愿卿之岁月安。5。看天上的月,吹人每日一句42人间烟火气,最抚凡人心幸福人生,无非四件事一是睡在自家床上二是吃父母做的菜三是听爱人讲情话四是跟孩子做游戏。人间烟火气,最抚凡人心!有家人在旁,粗茶淡饭,布衣蔬食,就是最温柔的时光。小时候家里穷,在老一
严重违纪违法,武夷市女老虎落马性贿赂40官上位前言反腐,关系着国家的发展稳定,关系着民心向背。反腐一直在路上,传递出国家坚决老虎苍蝇一起打的决心!在官场这个充满着名利的地方,一个女干部想要实现步步高升,只有一个方法,而且特别适全体业主当股东,十堰一小区居民当好自己的管家视频加载中十堰广电讯(全媒体记者马凯俊通讯员叶航)居民事自己管,小区事大家管,在十堰张湾区中岳华庭小区,业主自己成立物业公司,有效破解物业管理难题,通过业主自治,小区环境发生了很大做人太偏执,处处被排挤他确是明朝第一清官说到海瑞大家的第一印象就是清官,然而事实是,他不但是个清官,还是个偏执狂,为了保持清廉,他竟然自己种菜,自己打柴,他一年到头不吃肉菜,甚至有一次买了两斤肉,就闹到全省皆知的地步。这零工超市上岗今年44岁的江西宜春市袁州区居民彭冬华家里有6口人,且公公常年患肺病,2个孩子正在上学。为了维持生计的同时照顾家人,她一直想找份零工。但受限于只有初中学历,又没有擅长的职业技术,彭当服务先锋,建设现代化服务体系勇当服务先锋,建设现代化服务体系。春光明媚的三月,温暖的眼光照耀着万里铁道线,K3230次列车由洛阳开往福州站,终到福州站列车进行保洁卫生后折返洛阳站,列车的客运服务工作由郑州客运甲流该如何预防?甲流的病状有传染性强,出现呼吸道症状时在家休息观察,病情加重就去医院。接种疫苗这个,根据我周围人的情况是接种了也得了,如果确诊得了流感,应在发病开始的48小时内,尽快吃奥司他韦。如甘孜刘局长拼死拼活打造的知名度,被三根绳勒回去了!穷山恶水?前言近两年,甘孜州的知名度有很大的提升,很大程度上得益于甘孜文旅局局长刘洪。刘洪因为一张帅气的明星脸,给自己家乡的文化旅游代言,在大家心目中,已经成为甘孜的形象之一。然而,最近一桩苹果iOS16。4重磅更新,释出新机信息,明日发布会值得期待!在最新发布的iOS16。2正式版中,苹果引入了一项令人兴奋的新功能,名为快速安全响应。这项功能可以帮助用户及时修复可能存在的安全漏洞,而无需等待周期更久的正式版更新。据悉,在iOSCBA一日三消息,裁判上演迷之操作,姚明作重要决定,西热或下课昨晚,深圳击败北京首钢后,关于裁判的吹罚,球迷的争议就没停止过。深圳队沈梓捷,在一次盖帽的过程中,被裁判吹罚。事实上,这是个好球,封盖得干干净净。但裁判却吹罚沈梓捷阻挡犯规。作为主美国芯片被现实打脸,30多家芯企亏损,外媒芯片大战,美国已输美国芯片,被现实打脸了!美国英特尔高通等30多家半导体企业绩暴雷,先后宣布了停止扩产的决定。这种情况下,却出现了一个奇怪的现象,那就是我国中芯国际华虹半导体等企业于近日却宣布推进晶近三月销量腰斩,准备年销40万台的长安深蓝,被现实上了一课?我的目标,至少要把这个产品做到一万七八一个月的量,上市后第一个月至少收到5万台订单,击穿1530万元区间市场。这是去年长安新能源CEO邓承浩在接受媒体采访时放出的豪言壮语,如今再来