0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux内存管理暴涨的问题学习

OSC开源社区 来源:OSCHINA 社区 作者:京东云开发者-李遵 2022-11-24 09:45 次阅读

一、问题

近期我们运维同事接到线上 LB(负载均衡)服务内存报警,运维同事反馈说 LB 集群有部分机器的内存使用率超过 80%,有的甚至超过 90%,而且内存使用率还再不停的增长。接到内存报警的消息,让整个团队都比较紧张,我们团队负责的 LB 服务是零售、物流、科技等业务服务的流量入口,承接上万个服务的流量转发,一旦有故障影响业务服务比较多,必须马上着手解决内存暴涨的问题。目前只是内存报警,暂时不影响业务,先将内存使用率 90% 以上的 LB 服务下线,防止内存过高导致 LB 服务崩溃,影响业务,运维同事密切关注相关的内存报警的消息。

二、排查过程

经过开发同学通过 cat /proc/meminfo 查看 Slab 的内核内存可能有泄漏。

$ cat /proc/meminfo
MemTotal:       65922868 kB
MemFree:         9001452 kB
...
Slab:           39242216 kB
SReclaimable:   38506072 kB
SUnreclaim:       736144 kB
....

通过 slabtop 命令分析 slab 发现内核中 dentry 对象占比高,考虑到 dentry 对象跟文件有关,Linux 中一切皆可以为文件,这个可能跟 socket 文件有关,通过进一步排查发现 LB 服务上有个 curl 发送的 HTTPS 探测脚本,这个脚本存在 dentry 对象泄漏,并且在 curl 论坛上找到一篇文章确认了这个问题,这个文章说明了 curl-7.19.7 版本在发送 HTTPS 请求时,curl 依赖的 NSS 库存在 dentry 泄漏的 bug,我查看一下我们 curl 版本就是 7.19.7,问题终于真相大白了!!!

$ curl -V
curl 7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.15.3 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
Protocols: tftp ftp telnet dict ldap ldaps http file https ftps scp sftp
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz

$ rpm -aq|grep nss-
nss-util-3.16.1-3.el6.x86_64
nss-sysinit-3.16.1-14.el6.x86_64
nss-softokn-freebl-3.14.3-17.el6.x86_64
nss-softokn-3.14.3-17.el6.x86_64
nss-3.16.1-14.el6.x86_64
nss-tools-3.16.1-14.el6.x86_64

文章中介绍可以设置环境变量 NSS_SDB_USE_CACHE 修复这个 bug,我们验证通过了这个解决方案。

三、解决方案

1、目前先将探测脚本停止,在业务流量低峰时将内存使用率超过 90% 的服务先通过 drop_caches 清理一下缓存。

2、等大促过后,探测脚本中设置环境变量 NSS_SDB_USE_CACHE,彻底修复这个问题。

四、复盘和总结

这次内存暴涨的问题根本原因是 curl-7.19.7 依赖的 NSS 库存在 dentry 泄漏的 bug 导致的,探测脚本只是将这个问题暴露出来。这次问题由 Linux 内存泄漏引发的问题,因此以点带面再次系统学习一下 Linux 内存管理的知识非常有必要,对我们以后排查内存暴涨的问题非常有帮助。

1)Linux 内存寻址

Linux 内核主要通过虚拟内存管理进程的地址空间,内核进程和用户进程都只会分配虚拟内存,不会分配物理内存,通过内存寻址将虚拟内存与物理内存做映射。Linux 内核中有三种地址,

a、逻辑地址,每个逻辑地址都由一段 (segment) 和偏移量 (offset) 组成,偏移量指明了从段开始的地方到实际地址之间的距离。

b、线性地址,又称虚拟地址,是一个 32 个无符号整数,32 位机器内存高达 4GB,通常用十六进制数字表示,Linux 进程的内存一般说的都是这个内存。

c、物理地址,用于内存芯片级内存单元寻址。它们与从 CPU 的地址引脚发送到内存总线上的电信号对应。

Linux 中的内存控制单元 (MMU) 通过一种称为分段单元 (segmentation unit) 的硬件电路把一个逻辑地址转换成线性地址,接着,第二个称为分页单元 (paging unit) 的硬件电路把线性地址转换成一个物理地址。

22543ec2-6b2e-11ed-8abf-dac502259ad0.png

2)Linux 分页机制

分页单元把线性地址转换成物理地址。线性地址被分成以固定长度为单位的组,称为页(page)。页内部连续的线性地址被映射到连续的物理地址中。一般 "页" 既指一组线性地址,又指包含这组地址中的数据。分页单元把所有的 RAM 分成固定长度的页框(page frame),也成物理页。每一页框包含一个页 (page),也就是说一个页框的长度与一个页的长度一致。

页框是主存的一部分,因此也是一个存储区域。区分一页和一个页框是很重要的,前者只是一个数据块,可以存放任何页框或者磁盘中。把线性地址映射到物理地址的数据结构称为页表(page table)。页表存放在主存中,并在启用分页单元之前必须有内核对页表进行适当的初始化。 x86_64 的 Linux 内核采用 4 级分页模型,一般一页 4K,4 种页表:

a、页全局目录

b、页上级目录

c、页中间目录

d、页表

页全局目录包含若干页上级目录,页上级目录又依次包含若干页中间目录的地址,而页中间目录又包含若干页表的地址。每个页表项指向一个页框。线性地址被分成 5 部分。

226df718-6b2e-11ed-8abf-dac502259ad0.jpg

3)NUMA 架构

随着 CPU 进入多核时代,多核 CPU 通过一条数据总线访问内存延迟很大,因此NUMA架构应运而生,NUMA 架构全称为非一致性内存架构 (Non Uniform Memory Architecture),系统的物理内存被划分为几个节点 (node),每个 node 绑定不同的 CPU 核,本地 CPU 核直接访问本地内存 node 节点延迟最小。

2283d3d0-6b2e-11ed-8abf-dac502259ad0.png

可以通过lscpu 命令查看 NUMA 与 CPU 核的关系。

$ lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                32
On-line CPU(s) list:   0-31
Thread(s) per core:    2
Core(s) per socket:    8
Socket(s):             2
NUMA node(s):          2
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 62
Stepping:              4
CPU MHz:               2001.000
BogoMIPS:              3999.43
Virtualization:        VT-x
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              20480K
NUMA node0 CPU(s):     0-7,16-23      #这些核绑定在numa 0
NUMA node1 CPU(s):     8-15,24-31     #这些核绑定在numa 1

4)伙伴关系算法

Linux 内核通过著名伙伴关系算法为分配一组连续的页框而建立一种健壮、稳定的内存分配策略,是内核中一种内存分配器,并解决了内存管理外碎片的问题,外碎片是指频繁地请求和释放不同大小的一组连续页框,必然导致在已分配的页框的块分散了许多小块的空闲页框。

5)Slab 机制

slab机制的核心思想是以对象的观点来管理内存,主要是为了解决内部碎片,内部碎片是由于采用固定大小的内存分区,即以固定的大小块为单位来分配,采用这种方法,进程所分配的内存可能会比所需要的大,这多余的部分便是内部碎片。slab 也是内核中一种内存分配器,slab 分配器基于对象进行管理的,所谓的对象就是内核中的数据结构(例如:task_struct,file_struct 等)。

相同类型的对象归为一类,每当要申请这样一个对象时,slab 分配器就从一个 slab 列表中分配一个这样大小的单元出去,而当要释放时,将其重新保存在该列表中,而不是直接返回给伙伴系统,从而避免内部碎片。上面中说到的 dentry 对象就是通过 slab 分配器分配的一种对象。

slab 和伙伴系统是上下级的调用关系,伙伴关系按照页管理内存,slab 按照字节管理,slab 先从伙伴系统获取数个页的内存,然后切成分成固定的小块(称为 object),然后再按照声明的对象数据结构分配对象。

6)进程内存分布

所有进程都必须占用一定数量的内存,这些内存用来存放从磁盘载入的程序代码,或存放来自用户输入的数据等。内存可以提前静态分配和统一回收,也可以按需动态分配和回收。对于普通进程对应的内存空间包含 5 种不同的数据区:

a、代码段 (text):程序代码在内存中的映射,存放函数体的二进制代码,通常用于存放程序执行代码 (即 CPU 执行的机器指令)。

b、数据段 (data):存放程序中已初始化且初值不为 0 的全局变量和静态局部变量。数据段属于静态内存分配 (静态存储区),可读可写。

c、BSS 段 (bss):未初始化的全局变量和静态局部变量。

d、堆 (heap):动态分配的内存段,大小不固定,可动态扩张 (malloc 等函数分配内存),或动态缩减 (free 等函数释放)。

e、栈 (stack):存放临时创建的局部变量。

229d1a52-6b2e-11ed-8abf-dac502259ad0.jpg

Linux 内核是操作系统中优先级最高的,内核函数申请内存必须及时分配适当的内存,用户态进程申请内存被认为是不紧迫的,内核尽量推迟给用户态的进程动态分配内存。

a、请求调页,推迟到进程要访问的页不在 RAM 中时为止,引发一个缺页异常。

b、写时复制 (COW),父、子进程共享页框而不是复制页框,但是共享页框不能被修改,只有当父 / 子进程试图改写共享页框时,内核才将共享页框复制一个新的页框并标记为可写。

7)Linux 内存检测工具

a、free 命令可以监控系统内存

$ free -h
              total        used        free      shared  buff/cache   available
Mem:           31Gi        13Gi       8.0Gi       747Mi        10Gi        16Gi
Swap:         2.0Gi       321Mi       1.7Gi

b、top 命令查看系统内存以及进程内存

•VIRTVirtual Memory Size (KiB):进程使用的所有虚拟内存,包括代码(code)、数据(data)、共享库(shared libraries),以及被换出(swap out)到交换区和映射了(map)但尚未使用(未载入实体内存)的部分。

•RESResident Memory Size (KiB):进程所占用的所有实体内存(physical memory),不包括被换出到交换区的部分。

•SHRShared Memory Size (KiB):进程可读的全部共享内存,并非所有部分都包含在RES中。它反映了可能被其他进程共享的内存部分。

c、smaps 文件

cat /proc/$pid/smaps查看某进程虚拟内存空间的分布情况

0082f000-00852000 rw-p 0022f000 08:05 4326085    /usr/bin/nginx/sbin/nginx
Size:                140 kB
Rss:                 140 kB
Pss:                  78 kB
Shared_Clean:         56 kB
Shared_Dirty:         68 kB
Private_Clean:         4 kB
Private_Dirty:        12 kB
Referenced:          120 kB
Anonymous:            80 kB
AnonHugePages:         0 kB
Swap:                  0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
d、vmstat vmstat是 Virtual Meomory Statistics(虚拟内存统计)的缩写,可实时动态监视操作系统的虚拟内存、进程、CPU 活动。
## 每秒统计3次
$ vmstat13
procs -----------memory---------------- ---swap-- -----io---- --system-- -----cpu-----
 r  b    swpd   free   buff  cache       si   so    bi    bo   in   cs us sy id  wa st
 000233483840758304207955960001000010000
 000233483936758304207955960000105215690010000
 00023348392075830420795596000096615580010000

e、meminfo 文件

Linux 系统中/proc/meminfo这个文件用来记录了系统内存使用的详细情况。

$ cat /proc/meminfo
MemTotal:        8052444 kB
MemFree:         2754588 kB
MemAvailable:    3934252 kB
Buffers:          137128 kB
Cached:          1948128 kB
SwapCached:            0 kB
Active:          3650920 kB
Inactive:        1343420 kB
Active(anon):    2913304 kB
Inactive(anon):   727808 kB
Active(file):     737616 kB
Inactive(file):   615612 kB
Unevictable:         196 kB
Mlocked:             196 kB
SwapTotal:       8265724 kB
SwapFree:        8265724 kB
Dirty:               104 kB
Writeback:             0 kB
AnonPages:       2909332 kB
Mapped:           815524 kB
Shmem:            732032 kB
Slab:             153096 kB
SReclaimable:      99684 kB
SUnreclaim:        53412 kB
KernelStack:       14288 kB
PageTables:        62192 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:    12291944 kB
Committed_AS:   11398920 kB
VmallocTotal:   34359738367 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB
HardwareCorrupted:     0 kB
AnonHugePages:   1380352 kB
CmaTotal:              0 kB
CmaFree:               0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:      201472 kB
DirectMap2M:     5967872 kB
DirectMap1G:     3145728 kB







审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    11217

    浏览量

    208818
  • 内存
    +关注

    关注

    8

    文章

    2995

    浏览量

    73845
  • LINUX内核
    +关注

    关注

    1

    文章

    316

    浏览量

    21611
  • MMU
    MMU
    +关注

    关注

    0

    文章

    91

    浏览量

    18260
  • NSS
    NSS
    +关注

    关注

    0

    文章

    5

    浏览量

    6368

原文标题:Linux内存泄露案例分析和内存管理分享

文章出处:【微信号:OSC开源社区,微信公众号:OSC开源社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Linux内存管理是什么,Linux内存管理详解

    Linux内存管理 Linux内存管理是一个非常复杂的过程,主要分成两个大的部分:内核的
    的头像 发表于 05-11 17:54 5966次阅读
    <b class='flag-5'>Linux</b>的<b class='flag-5'>内存</b><b class='flag-5'>管理</b>是什么,<b class='flag-5'>Linux</b>的<b class='flag-5'>内存</b><b class='flag-5'>管理</b>详解

    深度解析Linux内存管理体系

    Linux内存管理的整体模式是虚拟内存管理(分页内存管理
    发表于 08-06 16:55 1700次阅读

    走进Linux内存系统探寻内存管理的机制和奥秘

    Linux 内存是后台开发人员,需要深入了解的计算机资源。合理的使用内存,有助于提升机器的性能和稳定性。本文主要介绍Linux 内存组织结构
    的头像 发表于 01-05 09:47 1594次阅读

    关于Linux内存管理的详细介绍

    Linux内存管理是指对系统内存的分配、释放、映射、管理、交换、压缩等一系列操作的管理。在
    发表于 03-06 09:28 1058次阅读

    Linux内核的内存管理详解

    内存管理的主要工作就是对物理内存进行组织,然后对物理内存的分配和回收。但是Linux引入了虚拟地址的概念。
    发表于 08-31 14:46 724次阅读
    <b class='flag-5'>Linux</b>内核的<b class='flag-5'>内存</b><b class='flag-5'>管理</b>详解

    《深入理解LINUX内存管理学习笔记

    《深入理解LINUX内存管理学习笔记1
    发表于 11-07 10:20

    郝健Linux内存管理学习笔记分享

    郝健 Linux内存管理学习笔记-第3节课
    发表于 06-10 08:55

    嵌入式Linux内存管理的知识

    这个内存管理的知识点还真的需要我们专门的去理解一下,今天大家一起来学习学习嵌入式Linux内存
    发表于 02-03 06:30

    linux内存管理

    公交,地铁,睡前必备,方便大家查阅,持续更新,敬请期待!---更新于2020-02-12linux 内存管理Linux内存初始化CPU是
    发表于 07-22 08:41

    linux内存管理机制浅析

    本内容介绍了arm linux内存管理机制,详细说明了linux内核内存管理,
    发表于 12-19 14:09 73次下载
    <b class='flag-5'>linux</b><b class='flag-5'>内存</b><b class='flag-5'>管理</b>机制浅析

    linux内存管理

    linux内存管理
    发表于 10-24 11:12 3次下载
    <b class='flag-5'>linux</b><b class='flag-5'>内存</b><b class='flag-5'>管理</b>

    内存价格持续暴涨,新内存管理方案出台势在必行

    对于用户来说,想在想买内存简直是困难的,因为它的价格暴涨的已经离谱到难以接受的地步,更夸张的是,这个疯涨势头还在继续。
    发表于 07-25 16:55 888次阅读

    你知道linux内存管理基础及方法?

    linux内存管理采取的分页存取机制,会将内存中不经常使用的数据块交换到虚拟内存中。linux
    发表于 04-28 17:12 1136次阅读

    Linux内存管理的基础知识科普

    Linux内存管理可谓是学好Linux的必经之路,也是Linux的关键知识点,有人说打通了内存
    的头像 发表于 06-08 15:24 2068次阅读

    Linux 内存管理总结

    一、Linux内存管理概述 Linux内存管理是指对系统内存
    的头像 发表于 11-10 14:58 492次阅读
    <b class='flag-5'>Linux</b> <b class='flag-5'>内存</b><b class='flag-5'>管理</b>总结