2019-08-21 18:34:12 ketaobaobao 阅读数 222

在Linux系统中,每个进程都独有一个虚拟地址空间(Virtual Address Space),由内核维护内存映射。为完成内存映射(虚拟内存地址映射到物理内存地址),内核为每一个进程维护一张页表。而页表存储在CPU的内存管理单元MMU中(即通过硬件完成了内存地址的查找)。

缺页异常

当进程访问的虚拟地址在页表中找不到时,就会产生缺页异常。此时会陷入内核空间完成物理内存分配、更新进程页表,然后恢复进程运行。

MMU以页为单位来管理内存,每个页通常为4KB大小,所以每一次内存映射需要关联4KB的整数倍的内存空间。

为了解决页表项过大问题,Linux提供多级页表(实际上是四级页表)和大页(HugePage)机制。

Linux虚拟地址空间分布

Linux的虚拟地址空间,大大增加了进程的寻址空间,32位系统的虚拟地址空间分布如图:

vas.gif

  • 只读段:只读,不可写;包括代码段、常量
  • 读/写段(或数据段):保存全局变量、动态变量
  • 堆:即平时说的动态内存,自下往上增长;堆内存由应用程序自己分配管理,依靠应用程序进行释放,但内核可将不常用数据换出到swap。大于128K的内存通过malloc()函数来分配(使用unmap()来释放),堆顶位置小于128K的内存通过brk()来分配(使用free()来释放)。
  • 文件映射区域:动态库、共享内存等映射物理空间的内存,自上往下增长;一般为mmap()函数所分配的虚拟地址空间
  • 栈:用于维护函数调用的上下文空间,一般为8M,ulimit -s查看
  • 内核虚拟空间:内核管理,对用户代码不可见。内核空间与用户空间的边界由TASK_SIZE控制。

对于64为Linux,内核空间占据顶部128T的虚拟地址空间,用户空间占据底部128T的虚拟地址空间。中间部分是未定义的。

另一张Linux虚拟地址空间分布图:

270929306664122.jpg

Linux内存回收

通过Linux虚拟地址空间分布,我们可以看出,Linux内存回收主要针对堆和文件映射区域。

  • 文件页:cache、buffer,通过内存映射的文件映射页
  • 匿名页:堆内存
  • 目录缓存和inode缓存

Linux内存回收时机

Linux提供2种内存回收时机:

  • 直接内存回收
  • 内核线程回收

直接内存回收

当发生内存分配,而此时的剩余空闲内存不足时,会执行立即内存回收。

内核线程回收

内核线程kswapd会定期扫描内存使用量,当剩余内存小于pages_free_low的值时,会进行内存回收,并确保可用内存高于pages_free_high。可通过修改/proc/sys/vm/min_free_kbytes文件的值来修改pages_free_min的值,另外两个值会自动计算得出。

kswapd0.png
NUMA架构中,每一个NUMA节点都会有一个kswapd线程。可通过numactl --hardware命令查看NUMA节点信息。

# cat /proc/sys/vm/min_free_kbytes
90112
# numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 20 21 22 23 24 25 26 27 28 29
node 0 size: 32642 MB
node 0 free: 188 MB
node 1 cpus: 10 11 12 13 14 15 16 17 18 19 30 31 32 33 34 35 36 37 38 39
node 1 size: 32768 MB
node 1 free: 68 MB
node distances:
node   0   1 
  0:  10  21 
  1:  21  10

Linux内存回收手段

Linux通过以下方式进行内存回收:

  1. 通过LRU算法回收文件页缓存:包括cache、buffer,通过内存映射的文件映射页;对于干净缓存直接回收、脏页回写到磁盘进行回收
  2. 程序不常访问的匿名页:通过swap机制回收堆内存
  3. OOM杀死oom_score大的程序:内存占用越大,oom_score越大,越容易被OOM;cpu占用越多,oom_score越小,越不容易被OOM;可通过/proc/$PID/oom_adj来影响oom_score的值,取值范围[-17, 15]
  4. 手动回收:通过修改/proc/sys/vm/drop_caches的值进行手动回收,最好再执行下sync命令回写脏页
    • 0:释放pagecache(即文件页)
    • 1:释放目录缓存和inodes
    • 3:释放pagecache(即文件页)、目录缓存和inodes

swappiness内存回收倾向

通过修改/proc/sys/vm/swappiness文件的值,使系统更倾向于回收匿名页或文件页,取值范围[0, 100]。
数值越大,越倾向于回收匿名页,越积极使用swap;
数值越小,越倾向于回收文件页,越消极使用swap;
但即使设置为0,仍然会使用swap。

NUMA

NUMA架构中,多处理器被划分到不同Node上,而同一个Node又进一步被换分为不同的内存域(Zone)。
在Linux中,默认开启NUMA,在我的系统(rhel6.5)上,64G的内存被划分为2个Node

# yum install -y numactl
# numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 2 4 6 8 10 12 14
node 0 size: 32757 MB
node 0 free: 237 MB
node 1 cpus: 1 3 5 7 9 11 13 15
node 1 size: 32767 MB
node 1 free: 137 MB
node distances:
node   0   1 
  0:  10  20 
  1:  20  10

当某node内存不足时,系统可以选择从其他node寻找空间内存,也可以选择从本node回收内存。具体偏好可以通过/proc/sys/vm/zone_reclaim_mode文件来控制。

  • 0:同时回收其他node和本node内存
  • 1:回收本node内存
  • 2:写脏数据回收本node内存
  • 4:匿名页回收本node内存

关闭NUMA

可以通过修改内核启动参数来禁用MUNA。

vi /boot/grub/grub.conf
...
kernel /boot/vmlinuz-2.6.18-128.1.16.0.1.el5 root=LABEL=DBSYS ro bootarea=dbsys rhgb quiet console=ttyS0,115200n8 console=tty1 crashkernel=128M@16M numa=off
...

swap查看

可通过cat /proc/$PID/status | grep VmSwap查看进程使用的swap情况。

也可通过smem命令查看进程使用的swap量。

查看swap使用最大的前10个进程:

# smem --sort swap -r | head -10
  PID User     Command                         Swap      USS      PSS      RSS 
12076 999      mysqld                        446756    60560    60894    61232 
22757 mysql    /usr/sbin/mysqld               61236     4360     4471     5520 
11864 root     /usr/bin/dockerd -H fd:// -    24848    16212    16212    16216 
  588 root     /usr/bin/containerd            13064     9688     9688     9692 
  590 root     /usr/bin/python3 /usr/share     7996        8        8       12 
  515 root     /usr/bin/python3 /usr/bin/n     7840        4        4        8 
12225 root     php-fpm: master process (/u     5988       52       71      116 
 4305 root     -bash                           3644     1852     2030     3196 
12368 www-data php-fpm: pool ww                3076     4668     6913     9184

查看每个用户的使用率

# smem -u
User     Count     Swap      USS      PSS      RSS 
nagios       1        0      704      728     1500 
chrony       1        0      700      885     2040 
dbus         1        0      892     1123     2508 
nobody      16        0     8832     9712    34300 
polkitd      1        0    11236    12009    14352 
root        28        0   194864   218192   269140

查看某进程(正则表达式匹配进程名):

# smem -P nginx
  PID User     Command                         Swap      USS      PSS      RSS 
 1423 root     nginx: master process /usr/        0      152      186     1160 
 1425 nobody   nginx: worker process              0      552      607     2144 
 1426 nobody   nginx: worker process              0      552      607     2144 
 1427 nobody   nginx: worker process              0      552      607     2144 
 1428 nobody   nginx: worker process              0      552      607     2144 
 1429 nobody   nginx: worker process              0      552      607     2144 
 1430 nobody   nginx: worker process              0      552      607     2144 
 1431 nobody   nginx: worker process              0      552      607     2144 
 1434 nobody   nginx: worker process              0      552      607     2144 
 1435 nobody   nginx: worker process              0      552      607     2144 
 1436 nobody   nginx: worker process              0      552      607     2144 
 1437 nobody   nginx: worker process              0      552      607     2144 
 1438 nobody   nginx: worker process              0      552      607     2144 
 1439 nobody   nginx: worker process              0      552      607     2144 
 1440 nobody   nginx: worker process              0      552      607     2144 
 1441 nobody   nginx: worker process              0      552      607     2144 
 1442 nobody   nginx: worker process              0      552      607     2140 
 9278 root     python /usr/bin/smem -P ngi        0     4628     5319     6820

nocache软件包

nocache软件包提供cachestatscachedel命令行工具,可查看、清理某文件在内存中的缓存。
bcc软件包中也提供一个cachestats命令行工具,可提供整个操作系统缓存的读写命中情况,另外还包含cachetop来提供每个进程的缓存命中情况。安装bcc软件包可能需要升级内核至4.1。

root@blog:~# cachestats /root/holiday.py 
pages in cache: 0/1 (0.0%)  [filesize=2.4K, pagesize=4K]
root@blog:~# cat /root/holiday.py &> /dev/null
root@blog:~# cachestats /root/holiday.py 
pages in cache: 1/1 (100.0%)  [filesize=2.4K, pagesize=4K]
root@blog:~# cachedel /root/holiday.py
root@blog:~# cachestats /root/holiday.py 
pages in cache: 0/1 (0.0%)  [filesize=2.4K, pagesize=4K]

/proc/sys/vm目录

/proc/sys/vm目录包含内存管理调优、buffer、cache管理的文件,这些参数用来调整Virtual Memory子系统的行为以及数据的写出(从RAM到ROM),具体如下。

文件 默认值 含义
/proc/sys/vm/admin_reserve_kbytes 3%的free pages与8MB中较小的值 系统中为拥有cap_sys_admin的权限(可以大致理解到root权限)的user预留的free memory数量。增大该值以保证root可登录并恢复系统。该值的修改需要考虑root登录后使用的工具(ssh、bash、ps、top、netstat等),一般推荐VSS+RSS。
/proc/sys/vm/block_dump 0,禁用 是否打开Block Debug模式,用于记录所有的读写及Dirty Block写回动作。
/proc/sys/vm/dirty_background_bytes 0 与dirty_background_ratio互斥,不可同时使用,设置了dirty_background_ratio之后,此项会变成0; 该文件定义脏数据的量,此时触发后台内核线程把脏数据写回磁盘
/proc/sys/vm/dirty_background_ratio 10 与dirty_background_bytes互斥,不可同时使用; 脏数据所占的页面,占包括free页面和可回收页面的在内的总可用页面数的百分比,此时触发后台内核线程将脏数据写回磁盘。这里说的总可用内存不等于系统的总内存。
/proc/sys/vm/dirty_expire_centisecs 3000(单位是1/100秒,即3s) 该文件表示如果脏数据在内存中驻留时间超过该值,后台内核线程会在下一次将把这些数据写回磁盘。
/proc/sys/vm/dirty_ratio 40 该文件表示如果进程产生的脏数据所占页面,占包括free页面和可回收页面的在内的总可用页面数的百分比,磁盘写操作的进程会自动把脏数据写回磁盘
/proc/sys/vm/dirty_writeback_centisecs 500(单位是1/100秒,即0.5s) 该文件表示后台内核线程周期性间隔多久把脏数据写回磁盘(即多少间隔唤醒一次)。
/proc/sys/vm/drop_caches 0 写入文件对应的值可使内核回收释放pagecache(即文件页,包括cache、buffer、通过内存映射的文件映射页)、目录缓存和inodes,从而得到更多空闲内存。 该操作是非破坏性的,脏数据不会被释放,应该在运行之前执行sync命令将所有缓存对象释放。 1:释放pagecache; 2:释放目录缓存和inodes; 3:释放pagecache、目录缓存和inodes;
/proc/sys/vm/hugetlb_shm_group 0 该文件表示允许使用hugetlb页创建System VIPC共享内存段的系统组ID。
/proc/sys/vm/legacy_va_layout 0 该文件表示是否使用最新的32位共享内存mmap()系统调用,Linux支持的共享内存分配方式包括mmap(),Posix,System VIPC。0,使用最新32位mmap()系统调用。1,使用2.4内核提供的系统调用。
/proc/sys/vm/min_free_kbytes 724(512M物理内存) 该文件表示强制Linux VM最低保留多少空闲内存(Kbytes)。
/proc/sys/vm/min_slab_ratio 5(%) 仅适用NUMA架构中; zone中可回收页面占总页面的百分比,超过后则进行回收; slab回收是基于每个zone/node的方式来触发的,这个过程可能不太快;
/proc/sys/vm/nr_hugepages 0 该文件表示系统保留的hugetlb页数。
/proc/sys/vm/nr_pdflush_threads 2(只读) 该文件表示当前正在运行的pdflush进程数量,在I/O负载高的情况下,内核会自动增加更多的pdflush进程。
/proc/sys/vm/overcommit_memory 0 该文件指定了内核针对内存分配的策略,其值可以是0、1、2。0,表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。1,表示内核允许分配所有的物理内存,而不管当前的内存状态如何。2,表示内核允许分配超过所有物理内存和交换空间总和的内存(参照overcommit_ratio)
/proc/sys/vm/overcommit_ratio 50(%) 该文件表示,如果overcommit_memory=2,可以过载内存的百分比,通过以下公式来计算系统整体可用内存。系统可分配内存=交换空间+物理内存*overcommit_ratio/100
/proc/sys/vm/page-cluster 3(2的3次方,8页) 该文件表示在写一次到swap区的时候写入的页面数量,0表示1页,1表示2页,2表示4页。
/proc/sys/vm/swapiness 60 该文件表示系统进行交换行为的程度,数值(0-100)越高,越可能发生磁盘交换。
/proc/sys/vm/vfs_cache_pressure 100 该文件表示内核回收用于directory和inode cache内存的倾向;缺省值100表示内核将根据pagecache和swapcache,把directory和inode cache保持在一个合理的百分比;降低该值低于100,将导致内核倾向于保留directory和inode cache;增加该值超过100,将导致内核倾向于回收directory和inode cache。

/proc/sys/vm中各文件含义大部分摘自:
https://www.cnblogs.com/xianbei/archive/2012/11/23/2783818.html

/proc/sys/vm中各文件含义部分内容参考:
https://blog.csdn.net/cassie_huang/article/details/80633328

smem命令:
https://linux.cn/article-4492-1.html

其他参考:

https://blog.csdn.net/weixin_33800593/article/details/90681825

https://cloud.tencent.com/developer/article/1004428

https://cloud.tencent.com/developer/article/1004429

2018-12-07 23:27:25 weixin_41950473 阅读数 6155

今天被叫着看一个性能问题,发现了一个很有意思的事情,当Linux的物理内存快被耗尽时,系统会把一些进程占用的内存转移swap区,当物理内存被释放一部分时,swap区的一些内存占用又慢慢回到mem区,但是mem区却不再是之前的满负荷状态,而是有一部分free的内存!

【17G大小进程压力测试结果】

  总资源消耗 内存类型 Used(G) Free(G) Total(G)
压力测试前 35.86 Mem 30.14 1.08 64
Swap 5.72 25.57
压力测试结束前期 34.78 Mem 12.78 18.45 64
Swap 22.00 9.30
压力测试结束后期 37.04 Mem 21.99 9.24 64
Swap 15.04 16.26

 

【总结】

  1. 当物理内存快被耗尽时,系统并没有崩溃,而是拿swap做临时内存,当两者都耗尽,系统OutofMemory
  2. 物理内存到达峰值,系统中可能一些不常用的进程内存占用被踢到swap区
  3. 当Mem区的资源进行释放时,被挪到swap的内存并不会全部回来的,随着系统或者程序的唤醒才会慢慢回到mem区
  4. Swap是内存不够时磁盘虚拟出来的内存,磁盘主要是I/O级别的操作并不是系统内核级别的操作,处理速度跟Mem区不是一个等级

 

 

2016-10-27 09:38:25 vbaspdelphi 阅读数 1998
  • 内存和swap图形
    这里写图片描述

  • 根据图片整理趋势对比

编号 mem变化趋势 swap变化趋势
1
2
3
4
5
6
7
8

* 趋势对比排列

编号 mem变化趋势 swap变化趋势
1
4
6
8
2
7
3
5

* 结论:
1. 内存使用无变化的时候,swap可能升也可能降
2. 内存使用上升的时候,swap有可能无变化,也有可能上升
3. 内存使用下降的时候,swap也会下降

备注:

  • 当前内存配置和使用情况
    这里写图片描述
    1. 当前swapniess是60,是不是说当内存使用了60%,也就是38GB之后,开始使用swap
    2. buffer和cache的使用确实不高,内存相当吃紧
    3. 内存的60%是38GB。
2017-05-20 19:06:26 zhaozijie51888 阅读数 280
关键字:教你认识Linux内存管理方式,分析Swap被程序占用情况

一、先了解一下linux对内存的管理方式:
在Linux里(别的系统也差不多),内存有物理内存和虚拟内存之说,物理内存是什么自然无需解释,虚拟内存实际是物理内存的抽象,多数情况下,出于方便性的考虑,程序访问的都是虚拟内存地址,然后操作系统会把它翻译成物理内存地址。很多人会把虚拟内存和Swap混为一谈,实际上Swap只是虚拟内存引申出的一种技术而已:操作系统一旦物理内存不足,为了腾出内存空间存放新内容,就会把当前物理内存中的内容放到交换分区里,稍后用到的时候再取回来,需要注意的是,Swap的使用可能会带来性能问题,偶尔为之无需紧张,糟糕的是物理内存和交换分区频繁的发生数据交换,这被称之为Swap颠簸,一旦发生这种情况,先要明确是什么原因造成的,如果是内存不足就好办了,加内存就可以解决,不过有的时候即使内存充足也可能会出现这种问题,比如MySQL就有可能出现这样的情况,解决方法是限制使用Swap:

shell> sysctl -w vm.swappiness=0 查看内存情况最常用的是free命令:
shell> free -m

total used free shared buffers cached
Mem: 32101 29377 2723 0 239 25880
-/+ buffers/cache: 3258 28842
Swap: 2047 0 2047

新手看到used一栏数值偏大,free一栏数值偏小,往往会认为内存要用光了。其实并非如此,之所以这样是因为每当我们操作文件的时候,Linux都会尽可能的把文件缓存到内存里,这样下次访问的时候,就可以直接从内存中取结果,所以cached一栏的数值非常的大,不过不用担心,这部分内存是可回收的,操作系统会按照LRU算法淘汰冷数据。除了cached,还有一个buffers,它和cached类似,也是可回收的,不过它的侧重点在于缓解不同设备的操作速度不一致造成的阻塞,这里就不多做解释了。
[color=red]知道了原理,我们就可以推算出系统可用的内存是[/color]free + buffers + cached:
shell> echo "2723 + 239 + 25880" | bc -l
28842

[color=red]至于系统实际使用的内存是[/color]used –buffers –cached:

shell> echo "29377 - 239 - 25880" | bc -l

3258
除了free命令,还可以使用sar命令:
shell> sar -r

kbmemfree kbmemused %memused kbbuffers kbcached

3224392 29647732 90.19 246116 26070160

3116324 29755800 90.52 245992 26157372

2959520 29912604 91.00 245556 26316396

2792248 30079876 91.51 245680 26485672

2718260 30153864 91.73 245684 26563540

shell> sar -W
pswpin/s pswpout/s

0.00 0.00

0.00 0.00

0.00 0.00

0.00 0.00

0.00 0.00

二、简单命令方式查看swap被那些进程占用:

简单脚本递归,列出swap使用pid ,top 10
for i in $( cd /proc;ls |grep "^[0-9]"|awk ' $0 >100') ;do awk '/Swap:/{a=a+$2}END{print '"$i"',a/1024"M"}' /proc/$i/smaps 2>/dev/null ; done | sort -k2nr | head -10

查看指定进程所使用的swap命令:
awk '/^Swap:/ {SWAP+=$2}END{print SWAP" KB"}' /proc/$(pid)/smaps

三、查看所有进程占用情况swap的脚本:

#!/bin/bash
# Get current swap usage for all running processes
# writted by xly

function getswap {
SUM=0
OVERALL=0
for DIR in `find /proc/ -maxdepth 1 -type d | egrep "^/proc/[0-9]"` ; do
PID=`echo $DIR | cut -d / -f 3`
PROGNAME=`ps -p $PID -o comm --no-headers`
for SWAP in `grep Swap $DIR/smaps 2>/dev/null| awk '{ print $2 }'`
do
let SUM=$SUM+$SWAP
done
echo "PID=$PID - Swap used: $SUM - ($PROGNAME )"
let OVERALL=$OVERALL+$SUM
SUM=0

done
echo "Overall swap used: $OVERALL"
}

getswap
#getswap|egrep -v "Swap used: 0"
2019-02-23 20:27:03 qq_35997094 阅读数 1529

Swap是Linux下的交换分区,类似Windows的虚拟内存,当物理内存不足时,系统可把一些内存中不常用到的程序放入Swap,解决物理内存不足的情况。
若系统安装时开辟的Swap空间太小,可通过手动创建Swap文件。

下面是创建使用SWAP的方法:

一、创建文件

dd if=/dev/zero of=/etc/swapfile bs=1024 count=4096000

SSH执行以上命令,创建一个名为vpppscom的4G 空文件(写0占用磁盘)。

二、制作为Swap文件

 mkswap /etc/swapfile

SSH执行以上命令,将生成的vpppscom制作为SWAP文件,若没有制作SWAP文件,执行下一步可能会出现:“swapon: vpppscom: read swap header failed: Invalid argument”错误。

三、让Swap文件生效

 swapon /etc/swapfile

SSH执行以上命令,使“vpppscom”这个Swap文件生效,并叠加进当前sawp空间中。

四、查看当前SWAP

swapon -s

SSH执行以上命令,查看当前swap的情况。

五、自动挂载
1)编辑/etc/fstab

vi /etc/fstab

2)按格式填入

/etc/swapfile swap    swap    defaults      0    0

按格式填入以上信息:

/dev/vda1 / ext3 noatime,acl,user_xattr 1 1
proc /proc proc defaults 0 0
sysfs /sys sysfs noauto 0 0
debugfs /sys/kernel/debug debugfs noauto 0 0
devpts /dev/pts devpts mode=0620,gid=5 0 0
/etc/swapfile swap swap defaults 0 0

至此未出现任何错误,那么SWAP就创建好了,使用free -m命令就可以看到了。

下面是销毁停用SWAP的方法:

1、先停止swap分区

/sbin/swapoff /etc/swapfile

2、删除swap分区文件

rm -rf /etc/swapfile

3、修改/etc/fstab文件,把

/etc/swapfile swap swap defaults 0 0

这行删除。
这样就能把手动增加的分区删除了。

PS:

1、增加删除swap的操作只能使用root用户来操作。

2、装系统时分配的swap分区貌似删除不了。

3、swap分区一般为内存的2倍,但最大不超过2G

然SWAP只是缓兵之计,实际使用中当然没能比的上真实的内存,所以要想得到更好的体验还是购买更大的内存吧!

没有更多推荐了,返回首页