Linux内存泄露案例分析和内存管理分享

2023-11-15

一、问题
近期我们运维同事接到线上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)的硬件电路把线性地址转换成一个物理地址。

在这里插入图片描述

2)Linux分页机制
分页单元把线性地址转换成物理地址。线性地址被分成以固定长度为单位的组,称为页(page)。页内部连续的线性地址被映射到连续的物理地址中。一般"页"既指一组线性地址,又指包含这组地址中的数据。分页单元把所有的RAM分成固定长度的页框(page frame),也成物理页。每一页框包含一个页(page),也就是说一个页框的长度与一个页的长度一致。页框是主存的一部分,因此也是一个存储区域。区分一页和一个页框是很重要的,前者只是一个数据块,可以存放任何页框或者磁盘中。把线性地址映射到物理地址的数据结构称为页表(page table)。页表存放在主存中,并在启用分页单元之前必须有内核对页表进行适当的初始化。

x86_64的Linux内核采用4级分页模型,一般一页4K,4种页表:

a、页全局目录

b、页上级目录

c、页中间目录

d、页表

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

在这里插入图片描述

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

在这里插入图片描述

可以通过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):存放临时创建的局部变量。
在这里插入图片描述

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命令查看系统内存以及进程内存

•VIRT Virtual Memory Size (KiB):进程使用的所有虚拟内存,包括代码(code)、数据(data)、共享库(shared libraries),以及被换出(swap out)到交换区和映射了(map)但尚未使用(未载入实体内存)的部分。
•RES Resident Memory Size (KiB):进程所占用的所有实体内存(physical memory),不包括被换出到交换区的部分。
•SHR Shared 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次

$ vmstat 1 3
procs -----------memory---------------- —swap-- -----io---- --system-- -----cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 233483840 758304 20795596 0 0 0 1 0 0 0 0 100 0 0
0 0 0 233483936 758304 20795596 0 0 0 0 1052 1569 0 0 100 0 0
0 0 0 233483920 758304 20795596 0 0 0 0 966 1558 0 0 100 0 0
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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux内存泄露案例分析和内存管理分享 的相关文章

  • 在Linux中断上下文中运行用户线程

    我正在编写一些定制的应用程序 并允许更改 Linux 内核中的中断处理程序代码 我有一个用户线程正在等待中断发生 如果发生中断 那么我要做的第一件事就是执行该用户线程 有什么办法让它发挥作用吗 Thanks 创建一个字符设备 这就是内核所做
  • 在 Ubuntu 16.04 上找不到 printf.c

    我最近切换到Ubuntu 16 04 我在用vscode作为 Ubuntu 上的 IDE 我配置了其他语言 但我无法做到这一点C C 我创建c cpp properties json launch json tasks json 当我开始编
  • linux x86 汇编语言 sys_read 调用的第一个参数应为 0 (stdin)

    我正在编写一个简单的汇编程序来从标准输入读取 如 scanf 这是我的代码 section bss num resb 5 section txt global start start mov eax 3 sys read mov ebx 0
  • C 程序从连接到系统的 USB 设备读取数据

    我正在尝试从连接到系统 USB 端口的 USB 设备 例如随身碟 获取数据 在这里 我可以打开设备文件并读取一些随机原始数据 但我想获取像 minicom teraterm 这样的数据 请让我知道我可以使用哪些方法和库来成功完成此操作以及如
  • Composer 安装要求

    我正在尝试将 Composer 安装到 Laravel 项目中 当我做的时候sudo composer install在项目目录中它显示了两个错误 Problem 1 Installation request for simplesoftw
  • Linux shell 脚本中的 while 循环超时

    这工作正常 无限循环 while TRUE do printf done 我在尝试着timeout this while loop与timeout命令 所有这些都不起作用 timeout 5 while TRUE do printf don
  • SONAR - 使用 Cobertura 测量代码覆盖率

    我正在使用声纳来测量代码质量 我不知道的一件事是使用 Cobertura 测量代码覆盖率的步骤 我按照以下步骤操作http cobertura sourceforge net anttaskreference html http cober
  • GCC 和 ld 找不到导出的符号...但它们在那里

    我有一个 C 库和一个 C 应用程序 尝试使用从该库导出的函数和类 该库构建良好 应用程序可以编译 但无法链接 我得到的错误遵循以下形式 app source file cpp text 0x2fdb 对 lib namespace Get
  • diff 文件仅比较每行的前 n 个字符

    我有2个文件 我们将它们称为 md5s1 txt 和 md5s2 txt 两者都包含a的输出 find type f print0 xargs 0 md5sum sort gt md5s txt 不同目录下的命令 许多文件被重命名 但内容保
  • 并行运行 make 时出错

    考虑以下制作 all a b a echo a exit 1 b echo b start sleep 1 echo b end 当运行它时make j2我收到以下输出 echo a echo b start a exit 1 b star
  • Godaddy 托管上的 CakePHP 控制台

    我一直在努力让我的 CakePHP 网站在 Godaddy 网格托管 帐户上运行 我的蛋糕应用程序设置是从帐户的子目录托管的 并且可以通过子域访问 我必须调整我的 htaccess 文件才能使其正常工作 现在我需要让 CakePHP 控制台
  • ansible 重新启动 2.1.1.0 失败

    我一直在尝试创建一个非常简单的 Ansible 剧本 它将重新启动服务器并等待它回来 我过去在 Ansible 1 9 上有一个可以运行的 但我最近升级到 2 1 1 0 并且失败了 我正在重新启动的主机名为 idm IP 为 192 16
  • 何时使用 pthread 条件变量?

    线程问题 看来 只有在其他线程调用 pthread cond notify 之前调用 pthread cond wait 时 条件变量才起作用 如果在等待之前发生通知 那么等待将被卡住 我的问题是 什么时候应该使用条件变量 调度程序可以抢占
  • Elasticsearch 无法写入日志文件

    我想激活 elasticsearch 的日志 当我运行 elasticsearch 二进制文件时 我意识到我在日志记录方面遇到问题 无法加载配置 这是输出 sudo usr share elasticsearch bin elasticse
  • 跟踪 Linux 程序中活跃使用的内存

    我想跟踪各种程序在特定状态下接触了多少内存 例如 假设我有一个图形程序 最小化时 它可能会使用更少的内存 因为它不会重新绘制窗口 这需要读取图像和字体并执行大量库函数 这些对象仍然可以在内存中访问 但实际上并没有被使用 类似的工具top它们
  • GLIBCXX_3.4.26 未找到在 BeagleBone 上运行交叉编译的程序

    我有以下程序 include
  • 仅打印“docker-container ls -la”输出中的“Names”列

    发出时docker container ls la命令 输出如下所示 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a67f0c2b1769 busybox tail f dev
  • 如何禁用 GNOME 桌面屏幕锁定? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 如何阻止 GNOME 桌面在几分钟空闲时间后锁定屏幕 我已经尝试过官方手册了在红帽 https access redhat com doc
  • 如何在 shell 脚本中并行运行多个实例以提高时间效率[重复]

    这个问题在这里已经有答案了 我正在使用 shell 脚本 它读取 16000 行的输入文件 运行该脚本需要8个多小时 我需要减少它 所以我将其划分为 8 个实例并读取数据 其中我使用 for 循环迭代 8 个文件 并在其中使用 while
  • 为什么 Linux perf 使用事件 l1d.replacement 来处理 x86 上的“L1 dcache misses”?

    在英特尔 x86 上 Linux用途 https stackoverflow com a 52172985 149138事件l1d replacements来实施其L1 dcache load misses event 该事件定义如下 计数

随机推荐

  • SpringBoot——配置文件的分类

    简单介绍 在之前我们写配置文件的时候 我们直接在项目中的resources下面编写的配置文件 其实除了在这个路径下编写配置文件 还可以在其他的地方编写配置文件 并且不同位置的配置文件在启动的时候的优先级也是不一样的 1 在resources
  • java list 默认排序_List集合排序(默认及自定义排序)

    一 java提供的默认list排序方法 主要代码 List list new ArrayList list add 王硕 list add 刘媛媛 list add 刘迪 list add 刘布 升序 Collections sort li
  • 数据类型与printf,scanf函数

    printf与scanf函数 printf函数是一个格式化输出函数 scanf 函数则是一个输入函数 其一般的调用格式 scanf 格式控制 地址列表 其中格式控制一般是双引号中间加一些字符 由 与格式符组成 用于控制输入的格式 比如 d
  • 内存条 udimm rdimm 等和 ECC 功能

    RDIMM registered DIMM Registered Dual In line Memory Module 带寄存器的双线内存模块 表示控制器输出的地址和控制信号经过Reg寄存后输出到DRAM芯片 控制器输出的时钟信号经过PLL
  • MySQL 查询语句大全

    目录 基础查询 直接查询 AS起别名 去重 复 查询 条件查询 算术运算符查询 逻辑运算符查询 正则表达式查询 模糊查询 范围查询 是否非空判断查询 排序查询 限制查询 分页查询 随机查询 分组查询 HAVING 高级查询 子查询 嵌套查询
  • vs显示行号

    工具 gt 选项 gt 文本编译器 gt 然后选择对应的编程语言 gt 在右侧 行号前的对勾打上确定即可
  • 【知识分享】Modbus通信协议详解

    一 协议 这里分两部分 Modbus和协议 首先什么是协议 百度解释下就是 意思是共同计议 协商 经过谈判 协商而制定的共同承认 共同遵守的文件 比如大学毕业找工作的时候 一般要签一份叫 三方协议 的 三方指自己 校方 企业 这份协议里规定
  • kali学习4——使用msfvenom制作exe木马

    使用msfvenom制作exe木马文件 1 msfvenom msfvenom是msfpayload msfencode的结合体 使用msfvenom制作木马的思路是 木马在目标机上执行后 向本机发送信息 而本机则需要开启监听状态 收到信息
  • 2021级新生个人训练赛第38场

    问题 A chicken 题目描述 小 x 非常喜欢小鸡翅 他得知 NSC 超市为了吸引顾客 举行了如下的活动 一旦有顾客在其他超市找到更便宜的小鸡翅 NSC 超市将免费送给顾客 1000g 小鸡翅 小 x 为了尽可能的省钱 走遍了各大超市
  • java Unreachable错误

    Unreachable code 错误 不可达代码 比如在循环的break或者return后面的代码就是不可达代码 因为执行它们之前就已经跳出循环了 只要把这段代码移到break return之前就好了 参考https blog csdn
  • np.mean()和np.std()函数

    一 np mean 函数定义 numpy mean a axis dtype out keepdims mean 函数功能 求取均值 经常操作的参数为axis 以m n矩阵举例 axis 不设置值 对 m n 个数求均值 返回一个实数 ax
  • kibana启动问题:Kibana server is not ready yet

    第一点 KB ES版本不一致 网上大部分都是这么说的 解决方法 把KB和ES版本调整为统一版本 第二点 kibana yml中配置有问题 通过查看日志 发现了Error No Living connections的问题 解决方法 将配置文件
  • Vue3通透教程【八】获取DOM、操作组件

    文章目录 写在前面 Vue2 ref 的使用 Vue3获取DOM Vue3操作组件 写在最后 写在前面 专栏介绍 凉哥作为 Vue 的忠实 粉丝输出过大量的 Vue 文章 应粉丝要求开始更新 Vue3 的相关技术文章 Vue 框架目前的地位
  • 【Linux】计算机操作系统和软硬件体系结构

    目录 1 冯诺依曼体系结构 1 1 中央处理器 CPU 2 操作系统 OS 2 1 操作系统的概念 2 2 操作系统的作用 2 3 操作系统如何进行管理 2 3 1 操作系统通过分级管理的方式 实现对整体的管理 2 3 2 管理的本质是对数
  • 如何使用chrome 浏览器自带截屏?

    1 ctrl shift c 2 ctrl shift p 3 输入 capture 4 选择capture full size screenshot 实现截取整个网页
  • enscape各种材质参数_它来了!Enscape专属素材库!

    ENSCAPE素材库 近两年风靡整个设计的渲染器 一款实时渲染软件Enscape 凭借入门低 成效快 效果逼真 从渲染界脱颖而出 用其他渲染器1 的时间渲出VRAY等老大哥级别90 的效果 作为建筑师的你会怎么选择呢 简单的分析了下渲染界最
  • MySQL connector/C++ 连接mysql效率低下解决

    这个问题 说解决也不算是被解决了 只能是让数据库插入的时候不会有像直接插入一样有那么多的问题了 我的解决方法是 开启mysql的事务 开始我也不知道是不是我的mysql配置优化的问题 WAMP统一安装 无限默认下一步的 在用PHP测试的时候
  • int与byte[]之间进行转换

    如何将int与byte 之间转换 int类型在内存中占4个字节 采用补码方式存储 而一个byte占一个字节 下面有两种方法进行转换 package cn fh vertxboot utils description int与Byte数组转换
  • 苹果app上架流程之傻瓜式教程剖析

    iOS开发者开发好一款APP之后 进行内测后没问题 下一步就是要上架AppStore了 一些开发者不知道该如何上架AppStore 下面 我们来说说iOS上架流程 以及如何快速上架AppStore 工具 1 iOS开发者账号 2 App U
  • Linux内存泄露案例分析和内存管理分享

    一 问题 近期我们运维同事接到线上LB 负载均衡 服务内存报警 运维同事反馈说LB集群有部分机器的内存使用率超过80 有的甚至超过90 而且内存使用率还再不停的增长 接到内存报警的消息 让整个团队都比较紧张 我们团队负责的LB服务是零售 物