admin 管理员组文章数量: 1184232
最近在复习总结linux内存优化相关知识,撰写此文,本文分别从以下几个部分展开,内存瓶颈有什么特征?如何去优化?以及怎么去衡量一个系统的内存情况,有什么指标和工具?内存泄漏怎么发现,内存回收相关知识,另外,还给出了一些常见的内存调优方法和内核调整参数。
另外,此文是我总结的思维导图导出后调整格式发布的,由于思维导图太大了,放图片的话会模糊,关于思维导图,如需要的话可私聊。
目录
内存瓶颈
特征
可用内存(available)持续减少,系统进程中kswapd进程频繁出现,同时Swap交换空间占用率持续增高
原因
-
一种是应用程序bug导致内存资源耗尽;另一种是确实内存资源不足
- 解决方法:针对第一种情况,需要从应用程序角度来排查问题。如果出现第二种情况,就要考虑增加内存资源了
-
一种是应用程序bug导致内存资源耗尽;另一种是确实内存资源不足
性能优化措施
- 关掉操作系统上用不到的服务
-
增加内存
- 需要注意的是在内存充足的情况下,如果再增加内存的话,内存瓶颈就会转为CPU瓶颈,因为CPU的运行速度也就是每秒内执行的机器指令数量是有限的
- 通过cgroups等措施限制进程内存使用
-
非必要不使用swap,如果必须用swap,调整Swapiness,降低内存回收时使用swap的机率
-
临时调整
- sysctl vm.swapiness=10 临时设置swapiness为10
-
永久调整
- vim /etc.sysctl.conf vm.swapiness=1
-
临时调整
-
减少内存的动态分配
- 使用bigpages、hugetlb和共享内存调优。
- 优化操作系统虚拟内存参数(如/proc/sys/vm)。
-
尽量使用缓存和缓冲区来访问数据
- 使用堆栈时,明确声明其内存空间来存储需要缓存的数据
- 用redis这类的外部缓存组件,来优化数据访问
-
保护核心应用不被OOM杀死
- 通过/proc/pid/oom_abj调整oom_score
- 保证内存紧张时,核心应用也不会被OOM KILL
内存指标
物理内存和逻辑内存
- 物理内存就是系统硬件提供的内存大小,是真正的内存。
- 逻辑内存就是为了满足物理内存的不足而提出的策略,它是利用磁盘空间虚拟出的一块逻辑内存区域,用作逻辑内存的磁盘空间被称为交换空间(Swap Space)
进程内存
-
虚拟内存VSS
- 已经申请,但是并未分配物理内存,也称作虚拟内存
- 包括了进程代码段、数据段、共享内存、已经申请的堆内存和已经换出的内存
-
共享内存
- 包括与其他进程共同使用的真实的共享内存
- 包括了加载的动态链接库以及程序的代码段等
-
常驻内存RSS
- 是进程实际使用的物理内存,不包括共享内存和swap
- 系统内存使用率是常驻内存占整个系统的总内存百分比
-
独占内存USS
- USS(Unique Set Size):进程独自占用的内存,它只计算了进程独自占用的内存大小,不包含任何共享的部分。默认是USS
-
按比例分配共享内存后的物理内存PSS(Proportional Set Size)
- 所有进程的PSS之和就是系统的内存使用量
- 它将共享内存的大小进行平均后,再分摊到各进程上去
-
swap内存
- swap是linux中时间换空间的一种操作,当swap空间占用多,频繁换入换出,会导致系统很卡顿
- swap是指通过 Swap 换出到磁盘的内存
-
虚拟内存VSS
系统内存
- 已用内存
- 剩余内存
-
共享内存
- 是通过 tmpfs 实现
- 大小也就是 tmpfs 使用的内存大小
-
可用内存
- 包括剩余内存和可回收缓存
-
缓存
- 磁盘读取文件的页缓存
- Slab 分配器中的可回收内存
-
缓冲区
- 缓存了将要写入磁盘的数据
- 内核就可以把分散的写集中起来,统一优化磁盘写入
-
缺页异常
-
次缺页异常
- 直接从系统物理内存分配
-
主缺页异常
- 从swap等需要磁盘IO介入的部分 分配
-
次缺页异常
-
sawp使用情况
-
换入速度
- 每秒换入的内存大小
- 换出速度
- 每秒换出的内存大小
- 已用空间
- 剩余空间
-
换入速度
内存调优常用工具
- free
-
smem
- 可以查看每个进程的物理内存使用情况
-
vmstat
- 可以观察内存的变化情况
-
pmap
- 查看进程的内存分布
- sar
- cachetop
- pmap
- cachestat
内存泄露
原因
-
使用完内存空间后忘记释放了
-
堆
- 当我们不知道使用的数据大小时,会使用malloc()在程序中动态分配内存
- 系统就会从内存空间的堆中分配内存
- 使用后忘记释放会出现内存泄漏风险
-
栈
- 分配的局部变量
- 由系统进行内存管理,不会出现内存泄漏问题
-
其他内存段
-
只读段
- 包括程序的代码和常量,只读的不会分配新内存,所以不会产生内存泄漏
-
数据段
- 包括全局变量和静态变量
- 在定义时候已经定好了大小,也不会产生memoryleak
-
内存映射段
- 包括动态链接库和共享内存
- 共享内存由程序动态分配和管理,因此在程序使用后忘记回收,就会导致和堆内存类似的泄露问题
-
只读段
-
堆
-
使用完内存空间后忘记释放了
影响
- 泄露的内存不断累积,造成内存浪费,系统无法为新进程分配内存,swap交换分区如打开的话会进行回收,并且剩余内存不多的话系统会开启内存回收,这将进一步导致IO问题
如何定位
- vmstat查看内存变化趋势
- memleak查看内存分配,从而定位是哪个程序内存异常
- 进入程序内部,查看代码,是否没有释放内存
生产环境
- 生产环境中除了一些程序错误导致内存迅速发生异常(这类用工具可以很容易发现),还可能会出现一些慢性积累过程,比如说一些缓慢的内存增长,用vmstat几乎看不到变化趋势,但是长此以往,对内存的消耗很大,这种情况下可以上监控,监控可以看到内存指标增长的趋势
为什么剩余内存很多的情况下,也会发生 Swap
-
处理器架构NUMA导致的
-
NUMA is(Non-Uniform Memory
Access) -
在 NUMA 架构下,多个处理器被划分到不同 Node 上,且每个 Node 都拥有自己的本地内存空间。
-
一个node内部的内存空间可分为不同的内存域(Zone)
- 直接内存访问区(DMA)
- 普通内存区(NORMAL)
- 伪内存区(MOVABLE)
- ....
- numactl --hardware可以查看处理器在不同node上的分布情况
-
当某一个node内存不足时,可以从其他node回收内存
- /proc/sys/vm/zone_reclaim_mode 可以调节回收方式
- 默认是0,可以从其他node找空闲内存或从本地回收内存
- 1表示内存回收只会发生在本地节点内
- 2表示可以回写Cache中脏数据到磁盘来回收内存
- 4表示可以使用swap回收内存
-
一个node内部的内存空间可分为不同的内存域(Zone)
-
NUMA is(Non-Uniform Memory
-
处理器架构NUMA导致的
内存回收
匿名页(动态分配的堆内存)
-
不可直接回收
- swap将匿名页先写到磁盘,然后再回收内存
- 当需要访问这部分匿名页时,再从swap中读取即可
-
不可直接回收
文件页
-
可直接回收
- 文件页(包括缓存和缓冲区)
-
不可直接回收
-
脏页
-
需要先写入磁盘再进行回收
- 通过系统调用fsnc同步写入
- 系统的内核线程pdflush刷新脏页
-
需要先写入磁盘再进行回收
-
脏页
-
可直接回收
如何解决回收内存会产生磁盘IO这种影响?
-
调整swapiness
- 回收匿名页(swapiness较大)一定会发生换入换出行为,产生磁盘IO,因此可以尝试降低 swappiness 的值,减少内存回收时 Swap 的使用倾向
- 回收文件页(swapiness较小)在回收干净页时不会发生磁盘写入行为,也就没有磁盘IO
-
尽早触发系统内存回收
- kswapd是后台内存回收机制,它是异步的,不会阻塞进程。
- 除非有必要使用swap,禁用swap
- 响应延迟敏感的应用,如果它们可能在开启 Swap 的服务器中运行,你还可以用库函数mlock() 或者 mlockall() 锁定内存,阻止它们的内存换出
-
调整swapiness
如何调整内存回收时回收的是哪种类型内存呢?
-
/proc/sys/vm/swappiness
- swappiness越小,越倾向于回收文件页
- swapiness越大,越倾向于回收匿名页
- 范围是0-100,表示的是一种倾向,当为0时也不是表示回收内存完全不用匿名页,当空心内存加上文件页仍小于pages_low,还是会用Swap
-
/proc/sys/vm/swappiness
内核里有一个线程kswapd0会定期扫描,进行内存回收
- 一旦剩余内存小于pages_min即页低阈值,就会触发内存的回收
- 页低阈值可以通过/proc/sys/vm/min_free_kbytes来设置
/proc/sys/vm/swappiness
- 表示使用Swap分区的概率
- 默认60,这是一个相对中和的配置,所以系统会根据实际运行情况,选择合适的回收类型
- 在一些数据库服务器上,如Redis、HBase机器上,应该设置0~10之间,表示最大限度使用物理内存。
- swappiness=100时表示积极使用Swap分区,并且把内存上的数据及时搬运到Swap空间里面
- swappiness=0时表示最大限度使用物理内存,然后才是Swap空间
/proc/sys/vm/panic_on_oom
- 表示内存不够时内核是否直接panic
-
默认值为0,表示当内存耗尽时,内核会触发OOM killer杀掉最耗内存的进程。
- 根据 oom_score来杀死,在/proc/${pid}/oom_score 越高的分数意味着越可能被kill,这个数值是根据oom_adj运算后的结果,是oom_killer的主要参考。
- /proc/[pid]/oom_adj 取值-17~15 越高的权重,意味着更可能被oom killer选中,-17表示禁止被kill掉。
-
设置为1表示在OOM时系统会panic(恐慌)
- 为了不让系统自动kill掉进程,需要设置此值为1。
/proc/sys/vm/nr_pdflush_threads
- 表示当前正在运行的pdflush进程数量,在I/O负载高的情况下,内核会自动增加更多的pdflush进程。
/proc/sys/vm/min_free_kbytes
- 表示强制Linux VM最低保留多少空闲内存
- 默认值为90112(88M物理内存,CentOS7版本),保持默认即可。
-
pages_low = pages_min*5/4
pages_high = pages_min*3/2
关于脏数据处理方法的一些内核参数
-
/proc/sys/vm/dirty_writeback_centisecs
- 控制内核的脏数据刷新进程pdflush的运行间隔
- 单位是(1/100)s。默认值是500,也就是5s
- 如果系统是持续地写入动作,那么建议降低这个数值,这样可以把尖峰的写操作削平成多次写操作;
- 如果系统是短期地尖峰式的写操作,并且写入数据不大且内存又比较富裕,那么应该增大此数值。
- 参数指定了当文件系统缓存脏数据数量达到系统内存百分之多少时,系统不得不开始处理缓存脏页
- 如果触发了这个设置,那么新的I/O请求将会被阻挡,直到脏数据被写进磁盘。这是造成I/O卡顿的重要原因,但这也是保证内存中不会存在过量脏数据的保护机制
- 在磁盘写入不是很频繁的场景,适当增大此值
- 如果是持续、恒定的写入场合,应该降低其数值。
-
/proc/sys/vm/dirty_writeback_centisecs
版权声明:本文标题:从零开始学Linux CentOS7.6内存管理:揭秘并打败共享内存泄露! 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/b/1772343919a3554854.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论