去年年底,我们曾经遇到过这个问题.在搞清楚这个问题的来龙去脉后,我尝试用本文来描述这个问题的根源和影响,并分享出来.看完要记得点赞或是评论哟!

  • 内存分配的过程

用户态的程序调用 malloc 函数申请内存. malloc 是一个库函数, 由 glibc 实现. glibc 内部实现了一个内存管理机制, 在用户态层对进程空间的内存分配进行管理.

不同的情况下, malloc 会调用系统调用 brk 或是 mmap 函数向内核申请内存区域.

当使用 mmap 申请内存成功后, 内核为这个新的内存区域创建一个VMA结点. 这个结点放入进程内存描述符 struct mm_struct 中的 mmap分量保存.

我们都知道 Linux 利用 Intel CPU 的保护模式 (虚拟地址模式) , 采用页表方式进行内存管理. 每个进程拥有自己的页面入口. 这个入口也记录在进程描述符中. 分量是 pgd.

对于新分配的内存区域, 内核并没有真的为其分配相应的物理内存. Linux 采用"用时才分配"的策略". 当进程访问这个新分配的内存区域时, 触发"缺页中断", 由这个中断陷入内核. 内核才开始为这个内存区域分配相应的物理内存. 物理内存是以页为单位分配的. 所有的页根据 buddyinfo 算法组织起来, 形成多个队列. 队列内的每个成员是相同大小的页面. 第一个队列的成员的大小是 2^0 * pagesize, 意味着是 4KB. 第二个队列的成员的大小是 2^1 * pagesize, 意味着是8KB. 最后一个队列的成员大小是 2^10 *pagesize, 意味着是 4MB. buddyinfo 从最适合的队列中取出页面分配出去. 所以, 通过"缺页中断", 进程请求内核向 buddyinfo 申请分配页面. 一旦分配成功, 这个新的内存区域与其对应页的关系被更新到了进程页表中.

注: 由于进程空间的内存是虚拟地址, 所以, buddyinfo 往往从 ORDER=0 的队列(2^0*pagesize)里为进程分配页面.即使进程需要多个页面,buddyinfo也只是从 ORDER=0 队列中分配出相应数量的单一页面.

到这里,来自用户态的进程申请的虚拟地址空间与物理内存关联到了一起,后续的程序可以访问这个虚拟地址空间了.

除了用户态进程需要申请内存.来自内核的内存申请也需要 buddyinfo进行分配.内核申请内存有两个来源:kmalloc 和 vmalloc .虽然kmalloc和vmalloc申请的仍是虚拟地址,但kmalloc 需要物理地址连续的空间,而vmalloc并不要求物理地址连续. kmalloc 用于小块内存分配,基于slab实现的.vmalloc 没有特别的限制.

下图表现了上面提到的各个术语之间的关系:(malloc, glibc, VMA, mm_struct, gdt, kmalloc, slab, vmalloc, buddyinfo)

  • 内存碎片

虽然执行内存分配的层次有很多,但记录了内存空间的使用情况,分进行管理工作的,只有glibc库和buddyinfo.由于内存是以大小不等的方式分配出去,并且,分配的内存区域可以释放和再分配.这不可避免的会出现碎片的问题.在 buddyinfo 出现内存碎片,会降低系统性能,并有可能影响系统的正常运行.

  • 内存碎片对性能的影响

维基在内存碎片概念的定义中举了一个例子,说明了内存碎片对性能的影响。

A subtler problem is that fragmentation may prematurely exhaust a cache, causing thrashing, due to caches holding blocks, not individual data. For example, suppose a program has a working set of 256 KiB, and is running on a computer with a 256 KiB cache (say L2 instruction+data cache), so the entire working set fits in cache and thus executes quickly, at least in terms of cache hits. Suppose further that it has 64 translation lookaside buffer (TLB) entries, each for a 4 KiB page: each memory access requires a virtual-to-physical translation, which is fast if the page is in cache (here TLB). If the working set is unfragmented, then it will fit onto exactly 64 pages (the page working set will be 64 pages), and all memory lookups can be served from cache. However, if the working set is fragmented, then it will not fit into 64 pages, and execution will slow due to thrashing: pages will be repeatedly added and removed from the TLB during operation. Thus cache sizing in system design must include margin to account for fragmentation.

理解这个例子,需要了解MMU,TLB和页表之间的关系。

前文提到了,Linux 利用 Intel CPU的保护模式,采用页表的方式对内存进行管理。 虚拟线性地址对应着某个页。这之间的对应关系存在于页表之中。 由于几乎每次对虚拟内存中的页面访问都必须先解析页,从而得到物理内存中的对应地址,所以页表操作的性能非常关键。因此,Intel MMU 系统结构中实现了一个TLB(translate lookaside buffer)作为一个将虚拟地址映射到物理地址的硬件缓存,当请求访问一个虚拟地址时,处理器将首先检查TLB是否缓存了该虚拟地址到物理地址的映射,如果命中则直接返回,否则,就需要通过页表搜索需要的物理地址。

TLB很小,只有64 entries 。当内存碎片化后,一个进程的虚拟线性地址空间对应于数量众多的小片的页,TLB不能容纳这么多的页面表项,这就意味在这个进程的运行期内,MMU在寻址时,TLB总是不能命中,而需要不断的更新。这就大大的降低了执行的效率。

上述的性能问题非常的隐晦,无法从一个或是数个直观的系统运行指标中发现。为了验证这个问题,使用了下述的程序进行了验证。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define KB (1024)
#define MB (1024 * KB)
#define GB (1024 * MB)
int main(int argc, char *argv[])
{
char *p;
int i = 0;
while ((p = (char *)malloc(70*KB)))
{
memset(p, 0, 70*KB);
if ( i>500000 )
break;
i++;
}
sleep(1);
return 0;

}


可以明显看到, LAB 112,dTLB-load-misses 要远大于同级别 benchmark的InternalBeta 132 .142,125,471 >> 3,799,475. 运行时间也多出了5秒 . 这个程序是没有任何高CPU操作的 . 在这个情况下慢了33%. 这是体现了LAB112的性能下降 .

内存碎片对kmalloc的影响

由于kmalloc要求分配连续的物理地址空间,当buddyinfo中没有大块的页,那么,无法得到满足的kmalloc会报错。在内核信息中可以看到 kmalloc fail.

Q: 如何确定系统已经碎片化?

A: cat /proc/buddyinfo

Q: 如何查看dTLB-load-misses?

A: perf stat -e dTLB-load,dTLB-load-misses ./brush_mem; perf top 可以查看当前系统最繁忙的函数

Q: 如何查看缺页中断?

A: ps -o majflt,minflt -C prog

Q: 虚拟线性地址如何对应到物理地址?

A:页表中包含有页的起始物理地址,通过虚拟地址在页表中查到对应的页,就可以得到最终的物理地址

order by 影响效率么_内存碎片对性能的潜在影响相关推荐

  1. order by 影响效率么_提升开发效率N倍的20+命令行神器

    图 by:石头@青海湖 关于作者:程序猿石头(ID: tangleithu),现任阿里巴巴技术专家,清华学渣,前大疆后端 Leader.以每篇文章都让人有收获为目的,欢迎关注,交流和指导! 背景 本文 ...

  2. 同一目录下有大量文件会影响效率吗_到底是什么原因才导致 select * 效率低下的?

    面试官:"小陈,说一下你常用的SQL优化方式吧." 陈小哈:"那很多啊,比如不要用SELECT *,查询效率低.巴拉巴拉..." 面试官:"为什么不要 ...

  3. 同一目录下有大量文件会影响效率吗_成考学习效率太低?可以从这7方面备考...

    距离成人高考的入学考仅存一个多月,怎样提高自己的学习高效率变成每名考生刻不容缓的难题.特别是在在工作中和学习分歧突显,各种各样影响持续的状况下,探索和结合自身的合理学习方式 ,借此机会提升学习效率,在 ...

  4. java字符串连接效率_关于java:字符串连接中的“+”是否会影响效率?

    本问题已经有最佳答案,请猛点这里访问. 我在java中使用过String,StringBuilder和StringBuffer. 我想到了这个问题,而我从效率的角度思考. 字符串连接中的"+ ...

  5. sql中使用“where 1=1 and ....“ 到底影响效率吗,回答不会也永远不会

    其实可以使用相当简单的方法判断, 假设 where 1=1真的降低了效率,对吧 那么我用1000个1=1连在后面怎么说效率也得下降个10倍吧 然而并没有 那又有人说, 1000个1=1 数据库优化器可 ...

  6. 华为官方鸿蒙系统发布会,手机显示hd是什么意思_手机显示hd有什么影响_手机hd怎么关闭...

    描述 手机显示hd是什么意思_手机显示hd有什么影响 手机屏幕顶端显示HD,说明开启了中国移动VoLTE高清语音业务.如需取消,进入设置-(更多连接设置)-移动网络-高清语音-关闭即可. 温馨提示:V ...

  7. java的if里有多个if_代码里写很多if会影响效率吗?

    看你怎么写 if. 嵌入很多层if的代码叫做"箭头代码",是一个anti-pattern. 这种代码会增加程序的循环复杂度 (Cyclomatic complexity) 具体可以 ...

  8. 参数变化_风机盘管参数变化对性能造成的影响

    参数变化对性能造成的影响: 1.风机盘管风量一定,供水温度一定,供水量变化时,制冷量随供水量的变化而变化,根据部分风机盘管产品性能统计,当供水温度为7℃,供水量减少到80%时,制冷量为原来的92%左右 ...

  9. 全国计算机电脑系统有问题吗,重装系统对电脑有损害吗_重装系统对电脑有什么影响-win7之家...

    当电脑遇到一些问题的时候,很多用户都会选择直接重装系统来解决,但是仍然有一部分用户担心重装系统对电脑有影响,不知道重装系统对电脑有损害吗?重装系统只对硬盘进行操作,对电脑本身其实是没有什么影响的,接下 ...

最新文章

  1. table control 光标定位控制
  2. 访问服务器 request.getheader(origin)为null_服务器磁盘不足,1分钟快速搞定!
  3. C++11 —— 简易的旋转锁类
  4. linux系统怎样写单片机程序,单片机知识是Linux驱动开发的基础之一以及如何学单片机...
  5. 从程序员到项目经理(三)
  6. can是什么时候处于显性_CAN总线边沿时间标准是什么?
  7. 深度学习与人工智能革命:part IV
  8. 电力猫服务器的网页,电力猫是如何工作的?
  9. uniapp 微信授权 登陆
  10. 吉大计算机学院田地,吉林大学研究生专业介绍:地质工程
  11. interpro 数据库
  12. R语言基础编程技巧汇编 - 13
  13. 云原生CI/CD:Tekton之trigger介绍
  14. 【品牌专场】跨越 X 突破,音视频聚力新机遇
  15. 高级程序猿是如何练成的
  16. 精通正则表达式第三章:正则表达式的特性和流派概览
  17. 2016计算机应用能力,2016全国专业技术人员计算机应用能力考试.doc
  18. RTOS——桌面mini网络时钟
  19. 加密javascript代码
  20. 云计算的主要服务形式,SaaS、PaaS和IaaS

热门文章

  1. 【Elasticsearch】class_cast_exception KeywordFieldMapper cannot be cast to ObjectMapper
  2. 仿造小红书页面代码html,jQuery仿小红书登录页,背景图垂直循环滚动登录页,向上循环滚动的动画,实现一张背景图片的无缝向上循环js滚动...
  3. Linux进程里运行新代码,linux调度器源码分析 - 新进程加入(三)
  4. php递归实现层级树状展开,PHP递归实现层级树状展开,php递归层级树状_PHP教程...
  5. dell 如何给raid分区_用U盘启动盘给Dell服务器装系统找不到RAID阵列解决办法
  6. Spring中如Service有多个实现类,它怎么知道该注入哪个ServiceImpl类?
  7. 详解SpringCloud中RabbitMQ消息队列原理及配置,一篇就够!
  8. 有啥不同?来看看Spring Boot 基于 JUnit 5 实现单元测试
  9. 移动开发利器——APICloud开发平台介绍
  10. ORA-01034: ORACLE not available