Linux内存泄露案例分析和内存管理分享
liebian365 2024-10-31 15:20 8 浏览 0 评论
本文作者:李遵举
一、问题
近期我们运维同事接到线上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
总结部分中一些内容来源于《深入理解Linux内核》,一些内容根据个人理解写出的,有不对地方欢迎指正,部分图片来源于网络
相关推荐
- 快递查询教程,批量查询物流,一键管理快递
-
作为商家,每天需要查询许许多多的快递单号,面对不同的快递公司,有没有简单一点的物流查询方法呢?小编的回答当然是有的,下面随小编一起来试试这个新技巧。需要哪些工具?安装一个快递批量查询高手快递单号怎么快...
- 一键自动查询所有快递的物流信息 支持圆通、韵达等多家快递
-
对于各位商家来说拥有一个好的快递软件,能够有效的提高自己的工作效率,在管理快递单号的时候都需要对单号进行表格整理,那怎么样能够快速的查询所有单号信息,并自动生成表格呢?1、其实方法很简单,我们不需要一...
- 快递查询单号查询,怎么查物流到哪了
-
输入单号怎么查快递到哪里去了呢?今天小编给大家分享一个新的技巧,它支持多家快递,一次能查询多个单号物流,还可对查询到的物流进行分析、筛选以及导出,下面一起来试试。需要哪些工具?安装一个快递批量查询高手...
- 3分钟查询物流,教你一键批量查询全部物流信息
-
很多朋友在问,如何在短时间内把单号的物流信息查询出来,查询完成后筛选已签收件、筛选未签收件,今天小编就分享一款物流查询神器,感兴趣的朋友接着往下看。第一步,运行【快递批量查询高手】在主界面中点击【添...
- 快递单号查询,一次性查询全部物流信息
-
现在各种快递的查询方式,各有各的好,各有各的劣,总的来说,还是有比较方便的。今天小编就给大家分享一个新的技巧,支持多家快递,一次能查询多个单号的物流,还能对查询到的物流进行分析、筛选以及导出,下面一起...
- 快递查询工具,批量查询多个快递快递单号的物流状态、签收时间
-
最近有朋友在问,怎么快速查询单号的物流信息呢?除了官网,还有没有更简单的方法呢?小编的回答当然是有的,下面一起来看看。需要哪些工具?安装一个快递批量查询高手多个京东的快递单号怎么快速查询?进入快递批量...
- 快递查询软件,自动识别查询快递单号查询方法
-
当你拥有多个快递单号的时候,该如何快速查询物流信息?比如单号没有快递公司时,又该如何自动识别再去查询呢?不知道如何操作的宝贝们,下面随小编一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号若干...
- 教你怎样查询快递查询单号并保存物流信息
-
商家发货,快递揽收后,一般会直接手动复制到官网上一个个查询物流,那么久而久之,就会觉得查询变得特别繁琐,今天小编给大家分享一个新的技巧,下面一起来试试。教程之前,我们来预览一下用快递批量查询高手...
- 简单几步骤查询所有快递物流信息
-
在高峰期订单量大的时候,可能需要一双手当十双手去查询快递物流,但是由于逐一去查询,效率极低,追踪困难。那么今天小编给大家分享一个新的技巧,一次能查询多个快递单号的物流,下面一起来学习一下,希望能给大家...
- 物流单号查询,如何查询快递信息,按最后更新时间搜索需要的单号
-
最近有很多朋友在问,如何通过快递单号查询物流信息,并按最后更新时间搜索出需要的单号呢?下面随小编一起来试试吧。需要哪些工具?安装一个快递批量查询高手快递单号若干怎么快速查询?运行【快递批量查询高手】...
- 连续保存新单号功能解析,导入单号查询并自动识别批量查快递信息
-
快递查询已经成为我们日常生活中不可或缺的一部分。然而,面对海量的快递单号,如何高效、准确地查询每一个快递的物流信息,成为了许多人头疼的问题。幸运的是,随着科技的进步,一款名为“快递批量查询高手”的软件...
- 快递查询教程,快递单号查询,筛选更新量为1的单号
-
最近有很多朋友在问,怎么快速查询快递单号的物流,并筛选出更新量为1的单号呢?今天小编给大家分享一个新方法,一起来试试吧。需要哪些工具?安装一个快递批量查询高手多个快递单号怎么快速查询?运行【快递批量查...
- 掌握批量查询快递动态的技巧,一键查找无信息记录的两种方法解析
-
在快节奏的商业环境中,高效的物流查询是确保业务顺畅运行的关键。作为快递查询达人,我深知时间的宝贵,因此,今天我将向大家介绍一款强大的工具——快递批量查询高手软件。这款软件能够帮助你批量查询快递动态,一...
- 从复杂到简单的单号查询,一键清除单号中的符号并批量查快递信息
-
在繁忙的商务与日常生活中,快递查询已成为不可或缺的一环。然而,面对海量的单号,逐一查询不仅耗时费力,还容易出错。现在,有了快递批量查询高手软件,一切变得简单明了。只需一键,即可搞定单号查询,一键处理单...
- 物流单号查询,在哪里查询快递
-
如果在快递单号多的情况,你还在一个个复制粘贴到官网上手动查询,是一件非常麻烦的事情。于是乎今天小编给大家分享一个新的技巧,下面一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号怎么快速查询?...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)