学习笔记-Linxu性能优化-内存

内存

   内存管理是操作系统最核心的功能之一,主要用于存储系统和应用程序的指令、数据、缓存等。

1. 内存映射

   我们购买电脑的考虑的一个重要参数就是内存,比方说,我的笔记本电脑的内存是 8 GB 的,而该内存通常指的是物理内存。物理内存也称为主存,大多数计算机的主存都是动态随机访问内存(DRAM)。只有内核才可以直接访问物理内存,所以内核给每个进程都提供了一个独立的虚拟地址空间,用于进程访问内存,更确切的说是虚拟内存。
   虚拟内存地址空间被分为内核空间和用户空间,进程在用户态时,只能访问用户空间;只有进入内核态时,才允许访问内核空间内存。虽然每个进程的地址空间中都包含了内核空间,但实际上这些内核空间关联的都是相同的物理内存。所以每个进程切换内核态后,还是可以方便的访问内核空间内存。
   实际并不是所有的内存都会分配物理内存,只有实际使用的虚拟内存才会分配物理内存,分配后的物理内存是通过内存映射管理的。

虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存]碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。大多数操作系统都使用了虚拟内存,如Windows家族的“虚拟内存”;Linux的“交换空间”等。

内存映射,其实就是将虚拟内存地址映射到物理内存地址上,内核为每个进程都维护了一个页表,记录虚拟地址和物理地址的映射关系。当进程访问的虚拟地址在页表中不存在时,系统会产生一个缺页异常,进入内核空间分配物理内存、更新进程的页表,最后返回用户空间,恢复进程的执行。

2. 如何查看内存的使用情况

在对内存有了基本的了解之后,我们应该如果查看系统的内存使用情况呢?通常可以使用 free或者vmstat工具来查看:

$ free
              total        used        free      shared  buff/cache   available
Mem:        1933076      309264      860000        5788      763812     1464292
Swap:             0           0           0

不过,free显示的是整个系统的内存使用情况。如果你想查看进程的内存使用,可以使用 top 或者 ps 工具。

如何理解内存中的Buffer和Cache

在之前通过free工具查看内存情况时,有一个指标buffer/cache 表示被使用的缓冲区和缓存之和, 我们可以使用 man free 命令查看 free 的文档,文档中对这两者的描述如下:

$ man free
buffers Memory used by kernel buffers (Buffers in /proc/meminfo)
cache  Memory used by the page cache and slabs (Cached and SReclaimable in /proc/meminfo)
  • buffers: 内核缓冲区用到的内存,是对原始磁盘块的临时存储,也就是用来缓存磁盘数据,通常不会特别大。
  • Cache: 页缓存和 Slab用到的内存,是从磁盘读取文件的页缓存,也就是用来缓存从文件读取的文件数据
    注意BufferCache不但可以用在读请求,也会用在写请求中(例如写合并:将多次分散的、小的写入合并成单次大的写入)。

内存泄露了如何处理

   对应用程序来说,动态内存的分配和回收,是既核心又复杂的一个逻辑功能模块。管理内存的过程中,也容易发生各种各样的事故,比如:

  • 没正确回收分配后的内存,导致了泄漏。
  • 访问的是已经分配内存边界外的地址,导致程序异常退出,等等。

1. 内存的分配和回收

   用户空间内存包含多个不同的内存段,比如只读段、数据段、堆、栈以及文件映射段等。这些内存段是应用程序使用内存的基本方式。
   栈内存由系统自动分配和管理,一旦程序运行超过这个局部变量的作用域,栈内存就会自动回收,所以不会产生内存泄漏。
   堆内存由应用程序自己分配和管理,除非程序退出,否则并不会被系统自动释放,而是需要应用程序明确调用库函数(free()) 进行释放,如果应用程序没有正确释放堆内存,就会造成内存泄漏。
   只读段,包括程序的代码和常量,由于是只读的,不会再去分配新的内存,所以不会造成内存泄漏。
   数据段,包括全局变量和静态变量,这些变量在定义时就已经确定了大小,所以也不会产生内存泄漏。
   内存映射段,包括动态链接库和共享内存,其中共享内存由程序动态分配和管理,所以如果程序在分配后忘记回收,就会导致内存泄漏。
  内存泄漏的危害极大,这些忘记释放的内存,不仅应用程序自己无法访问,系统也不能将它们再次分配给其他应用,不断累积甚至会耗尽系统内存。
  虽然系统可能会通过OOM机制杀死进程,但是在OOM之前就已经引发了一连串的反应,导致严重的性能问题。比如无法分配内存给其他需要内存的进程;内存不足又会触发系统的缓存回收以及SWAP机制,从而进一步导致IO性能问题等。

2. 内存问题的定位和分析

  我们可以通过 vmstat观察空闲内存是否一直在变小,但是这并不能说明有内存泄漏,因为应用程序 运行中需要的内存也可能会增大。那怎么确定是不是内存泄漏呢?或者有没有简单的办法找出让内存增长的进程,并定位增长内存用在哪?
  可以使用 memleak 工具跟踪系统或指定进程的内存分配、释放请求,然后定期输出一个未释放内存和相应调用栈的汇总情况。

为什么系统的Swap变高了

  系统的内存资源紧张时,会导致两种结果,内存回收和OOM杀死进程。内存回收,就是系统释放可以回收的内存,比如缓存和缓冲区。它们在内存管理中,叫做内存页,大部分文件页,都可以直接回收,以后有需要从磁盘重新读取即可,而那些脏页,得先写入磁盘,才能进行内存释放。
  脏页的刷新有两种方式,在应用程序中,通过系统调用fsync将脏页同步到磁盘中;由内核线程pdflush刷新脏页。
  除了缓存和缓冲区,通过内存映射获取的文件映射页,也是一种常见的文件页。它也可以被释放掉,下次访问的时候重新进行读取。除了文件页,应用程序动态分配的堆内存(匿名页)是不是也可以进行回收呢?
由于这些匿名页很可能会再次访问,所以不能直接回收,但是这些在分配之后很少访问的内存,似乎是一种资源的浪费,所以可以将这些暂时先存到磁盘中,释放内存给其他更需要的内存,这就是Swap机制。Swap把这些不常访问的内存先写到磁盘中,然后释放这些内存,给其他更需要的进程使用。再次访问这些内存时,重新从磁盘中读取即可。

Swap原理

swap原理实际就是将一块磁盘空间当做内存来使用,即使服务器的内存不足,它也能通过另一个方式扩大服务器的内存,它包括换入和换出两个过程。

  • 换出: 把进程暂时不使用的内存数据存储到磁盘中,并且释放这些数据占用的内存。
  • 换入:在进程再次访问这些内存时,把它们从磁盘中读取到内存中来。
      既然 swap是为了回收内存,那么什么情况下linux会触发内存回收的动作呢?一个最容易想到的场景就是,有大块内存的分配请求,但是剩余内存不足,为了满足分配,会回收一部分内存,这个过程叫做直接内存回收。除此之外,linxu还会通过一个内核线程(kswapd0)定期回收内存, 为了衡量内存使用情况,linux定义了三个内存阈值,分别为页最小阈值页低阈值页高阈值。该内核线程会定期扫描内存使用情况,然后根据内存阈值进行回收操作:
  • 剩余内存小于页最小阈值时,说明进程可用内存耗尽了, 只用内核才允许分配内存。
  • 剩余内存在页最小阈值和页低阈值之间,说明内存压力过大,此时内核线程会回收线程,直到剩余内存大于页高阈值。
  • 剩余内存在页低阈值和页高阈值之间,说明内存有一定压力,但还能接受内存分配的请求。
  • 剩余内存大于页高阈值,说明内存毫无压力。

分析步骤

  1. 通过 sar 工具查看内存各个指标的变化情况,确定内存的分配情况。
$ sar -r -S 1
Linux 5.10.84-10.4.al8.x86_64 (iZ2ze46nbb45cm0vd4oujfZ)         07/22/2023      _x86_64_        (1 CPU)

07:09:43 PM kbmemfree   kbavail kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
07:09:44 PM    423456   1329504   1509620     78.09    168912    824284   1363628     70.54    650336    675748       248

07:09:43 PM kbswpfree kbswpused  %swpused  kbswpcad   %swpcad
07:09:44 PM         0         0      0.00         0      0.00
  1. 如果缓冲区不断增大,通过 cachetop命令查看哪些进程导致缓冲区增大。缓冲区属于可回收内存,内存不够用时应该会回收这部分内存,为什么可能会导致swap 升高呢?在swap原理中有对linux的内存阈值有过简单的介绍,可以通过 watch -d grep -A 15 'Normal' /proc/zoneinfo 命令查看内存阈值、文件页、匿名页的大小变化。
  2. 也可以通过 smem --sort swap 查看使用 swap 最多的进程,然后进行详细的剖析。

如何快准狠的找出系统内存问题

内存性能指标

  为了分析内存的性能瓶颈,首先应该知道如何衡量内存的性能,也就是性能指标。
  首先就是系统的内存使用情况,包括已用内存、剩余内存、共享内存、可用内存、缓存和缓冲区的用量等。
  然后是进程内存使用情况,比如进程的虚拟内存、常驻内存、共享内存已经swap内存等等。
  第三个重要的指标就是 swap使用情况,比如 swap已用空间、剩余空间、换入和换出速度等。

内存性能指标

内存性能工具

性能工具

为了迅速定位内存问题,通常先运行几个覆盖面比较大的性能工具,比如 freetopvmstatpidstat等。

  1. 先用 freetop,查看系统的整体内存使用情况。
  2. 再用 vmstatpidstat 查看一段时间的趋势,从而判断内存问题的类型。
  3. 最后进行详细的分析,比如内存分配分析、缓存\缓冲区分析、具体进程的内存使用分析等。

小结

内存调优最重要的就是,保证应用程序的热点数据放到内存中,并尽量减少换页和交换。常见的优化思路就这么几种。

  1. 最好禁止 swap。如果要必须开启的话,降低 swappiness的值,减少回收时 swap的使用倾向。
  2. 减少内存的动态分配。比如,可以使用内存池,大页等。
  3. 尽量使用缓存和缓冲区访问数据。比如使用堆栈明确声明内存空间,来存储需要缓存的数据,或者使用外部缓存组件,优化数据访问。
  4. 使用cgroups等方式限制进程的内存使用情况,确保系统内存不会被异常进程耗尽。
  5. 通过 /proc/pid/oom_adj 调整核心线程的 oom_score。这样,可以保证即使内存紧张,核心应用也不会被OOM杀死。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容