linux中内存升高了如何解决
在Linux下频繁存取文件后,物理内存会很快被用光,当程序结束后,内存不会被正常释放,而是一直作为caching。那么内存不断升高之后如何解决呢?
这个时候最简单有效的就是自己手动释放内存,或者写一个释放内存的脚本去做这个事情.
linux中的 /proc
是一个虚拟文件系统,我们可以通过对它的读写操作做为与kernel
实体间进行通信的一种手段。也就是说可以通过修改 /proc
中的文件,来对当前kernel
的行为做出调整。那么我们可以通过调整/proc/sys/vm/drop_caches
来释放内存。
首先,查看/proc/sys/vm/drop_caches的值:
> cat /proc/sys/vm/drop_caches
0
默认值为0. 这里需要解释下drop_caches
的值可以是0-3之间的数字,代表不同的含义:
0:不释放(系统默认值).
1:释放页缓存.
2:释放dentries和inodes.
3:释放所有缓存.
然后,运行sync命令.
> sync
手动执行sync命令(描述:sync 命令运行 sync 子例程。如果必须停止系统,则运行sync 命令以确保文件系统的完整性。sync 命令将所有未写的系统缓冲区写到磁盘中,包含已修改的 i-node、已延迟的块 I/O 和读写映射文件)最后,输入手动释放内存的命令.
> echo 1 > /proc/sys/vm/drop_caches
等到我们释放完内存后改回去让系统重新自动分配内存.
> echo 0 >/proc/sys/vm/drop_caches
通过查看free -m
看内存是否已经释放掉了。如果我们需要释放所有缓存,就输入下面的命令:
> echo 3 > /proc/sys/vm/drop_caches
在Linux系统下,我们一般不需要去释放内存,因为系统已经将内存管理的很好。但是,有的时候内存会被缓存占用掉,导致系统使用SWAP空间影响性能,例如当你在linux下频繁存取文件后,物理内存会很快被用光,当程序结束后,内存不会被正常释放,而是一直作为caching。,此时就需要执行释放内存(清理缓存)的操作了。
Linux系统的缓存机制设计的很棒,会针对dentry(用于VFS,加速文件路径名到inode的转换)
、Buffer Cache(针对磁盘块的读写)
和Page Cache(针对文件inode的读写)
进行缓存操作。在进行了大量文件操作之后,缓存会把内存资源基本用光。然而此时呢我们文件操作已经完成,这部分缓存已经用不到了。这个时候,我们难道只能眼睁睁的看着缓存把内存空间占据掉吗?所以,我们还是有必要来手动进行Linux下释放内存的操作,其实也就是释放缓存的操作了。
/proc
是一个虚拟文件系统,我们可以通过对它的读写操作做为与kernel
实体间进行通信的一种手段.也就是说可以通过修改/proc
中的文件,来对当前kernel
的行为做出调整.那么我们可以通过调整/proc/sys/vm/drop_caches
来释放内存。要达到释放缓存的目的,我们首先需要了解下关键的配置文件/proc/sys/vm/drop_caches
。这个文件中记录了缓存释放的参数,默认值为0,也就是不释放缓存。
一般复制了文件后,可用内存会变少,都被cached
占用了,这是linux为了提高文件读取效率的做法:为了提高磁盘存取效率, Linux做了一些精心的设计, 除了对dentry
进行缓存(用于VFS,加速文件路径名到inode的转换), 还采取了两种主要Cache方式:Buffer Cache
和Page Cache
。前者针对磁盘块的读写,后者针对文件inode的读写。这些Cache有效缩短了 I/O系统调用(比如read,write,getdents)的时间。”
释放内存前先使用sync命令做同步,以确保文件系统的完整性,将所有未写的系统缓冲区写到磁盘中,包含已修改的 i-node、已延迟的块 I/O 和读写映射文件。否则在释放缓存的过程中,可能会丢失未保存的文件。
然后通过:
> free -m
total used free shared buff/cache available
Mem: 15883 965 1057 2 13860 10172
Swap: 0 0 0
- total 内存总数
- used 已经使用的内存数,一般情况这个值会比较大,因为这个值包括了cache 应用程序使用的内存
- free 空闲的内存数
- shared 多个进程共享的内存总额
- buffers缓存,主要用于目录方面,inode值等(ls大目录可看到这个值增加)
- cached 缓存,用于已打开的文件
这里的可以用内存就是free memory buffers cached
。
top
命令用来查看具体进程消耗的内存空间。
> top
top - 22:49:09 up 6 days, 11:04, 1 user, load average: 0.05, 0.11, 0.13
Tasks: 233 total, 1 running, 232 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.1 us, 0.1 sy, 0.0 ni, 99.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 19264560 total, 5250212 free, 820192 used, 8794156 buff/cache
KiB Swap: 0 total, 0 free, 0 used. 10768300 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
4709 root 20 0 3101008 119788 35696 S 1.3 0.7 182:29.21 kubelet
1527 root 20 0 3362068 113276 25004 S 1.0 0.7 192:35.61 dockerd
1864 root 10 -10 238384 126872 9672 S 1.0 0.8 131:04.13 AliYunDun
1849 root 20 0 2401924 53416 12728 S 0.7 0.3 35:12.78 docker-containe
18139 root 20 0 162124 2408 1612 R 0.7 0.0 0:00.34 top
3190 root 20 0 700332 46788 5284 S 0.3 0.3 7:27.10 salt-minion
11669 root 20 0 142088 27076 13304 S 0.3 0.2 6:51.16 kube-proxy
17152 root 10 -10 436896 2748 2264 S 0.3 0.0 3:39.81 AliSecGuard
1 root 20 0 44608 4984 2588 S 0.0 0.0 2:05.33 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.56 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 0:02.84 ksoftirqd/0
5 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H
7 root rt 0 0 0 0 S 0.0 0.0 0:01.97 migration/0
8 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_bh
9 root 20 0 0 0 0 S 0.0 0.0 4:21.17 rcu_sched
10 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 lru-add-drain
11 root rt 0 0 0 0 S 0.0 0.0 0:01.44 watchdog/0
12 root rt 0 0 0 0 S 0.0 0.0 0:01.21 watchdog/1
13 root rt 0 0 0 0 S 0.0 0.0 0:06.15 migration/1
通过%MEM
列,就可以查看哪几个进程占用了大量的内存,在缓解内存不足的紧急情况时,可以终止这些占用内存较多的进程。
top命令中有以下与内存相关的数据列:
PID:进程的ID.
USER:进程所有者.
PR:进程的优先级别,越小越优先被执行.
NInice:值.
VIRT:进程占用的虚拟内存.
RES:进程占用的物理内存.
SHR:进程使用的共享内存.
S:进程的状态。S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值为负数.
%CPU:进程占用CPU的使用率.
%MEM:进程使用的物理内存和总内存的百分比.
TIME+:该进程启动后占用的总的CPU时间,即占用CPU使用时间的累加值。.
COMMAND:进程启动命令名称.
交换空间
使用free命令可以查看内存的总体使用,显示的内容也包括交换分区的大小,可以使用swapon,swapoff,命令开启或关闭交换空间,交换空间是磁盘上的文件,并不是真正的内存空间。
例如:关闭交换分区
> swapoff -a
> free
total used free shared buffers cached
Mem: 12260128 6497332 5762796 1256 312980 2191960
-/+ buffers/cache: 3992392 8267736
Swap: 0 0 0
此时交换分区显示全为0,说明系统没有开启交换分区。swapon命令可以启用交换分区。当内存不足时,系统会选择通过将部分不常被访问的内存页交换到内存空间,或者删除部分cache的文件来释放内存空间。
系统的可用内存一般等于物理内存 + 交换分区。交换分区在磁盘上, 因此速度比内存读写要慢得多。
交换分区实际上就是磁盘上的文件,可以通过mkswap命令来创建交换空间。
内核态内存占用
> slabtop
slab系统用来处理系统中比较小的元数据,如文件描述符等,进而组织内核态的内存分配。
一个slab包含多个object,例如dentry这些数据结构就是object,可以通过slabtop命令查看系统中活动的object的数量与内存占用情况,从而了解哪些数据结构最占用内核态的内存空间。
例如:使用slabtop命令查看内核数据结构及内存占用
Active / Total Objects (% used) : 1222616 / 1575898 (77.6%)
Active / Total Slabs (% used) : 39945 / 39945 (100.0%)
Active / Total Caches (% used) : 67 / 125 (53.6%)
Active / Total Size (% used) : 276332.00K / 318115.77K (86.9%)
Minimum / Average / Maximum Object : 0.01K / 0.20K / 15.75K
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
848211 516003 60% 0.10K 21749 39 86996K buffer_head
266406 266158 99% 0.19K 6343 42 50744K dentry
75300 73560 97% 0.63K 3012 25 48192K proc_inode_cache
70224 70224 100% 0.96K 2128 33 68096K ext4_inode_cache
56960 56489 99% 0.06K 890 64 3560K kmalloc-64
52530 50791 96% 0.04K 515 102 2060K ext4_extent_status
30702 29066 94% 0.19K 731 42 5848K kmalloc-192
27076 22278 82% 0.55K 967 28 15472K radix_tree_node
26532 26532 100% 0.11K 737 36 2948K sysfs_dir_cache
20910 20910 100% 0.05K 246 85 984K shared_policy_node
12712 12712 100% 0.57K 454 28 7264K inode_cache
11536 10815 93% 0.07K 206 56 824K anon_vma
9088 7840 86% 0.03K 71 128 284K kmalloc-32
6752 3567 52% 0.25K 211 32 1688K kmalloc-256
6656 6656 100% 0.02K 26 256 104K kmalloc-16
6560 4747 72% 0.12K 205 32 820K kmalloc-128
6656 6656 100% 0.02K 26 256 104K kmalloc-16
这里通常需要关注有两点:
- 哪些数据结构的内存占用最大,
- 哪些类型的数据结构对应的object最多,比如inode多代表文件系统被大量引用等。
该交互命令支持的选项与排序标准有:
选项:
--delay=n, -d n 每隔n秒刷新信息
--once, -o 只显示一次
--sort=S, -s S 按照S排序,其中S为排序标准
排序标准(shift + 对应的键):
a:根据active objects数量高低排序
b:根据 objects / slab高低来排序
c:根据cache大小排序
l:根据slab数量排序
v:根据active slabs数量排序
n:按 name 排序
o:按照 objects 数量排序
p:按照 pages / slab 的值排序
s:按照 object 大小排序
u:按照 cache 使用量排序
查看内存使用的动态变化
vmstat命令可以查看内存使用的动态变化,
例如: 使用vmstat动态监视内存变动
> vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 5542996 2712 9796396 0 0 34 24 1 1 1 0 99 0 0
0 0 0 5542880 2856 9796684 0 0 148 0 1720 2794 0 0 99 0 0
0 0 0 5543084 2864 9796680 0 0 0 36 1500 2625 0 0 100 0 0
0 0 0 5543084 2864 9796680 0 0 4 0 1849 2919 1 0 99 0 0
0 0 0 5543076 2864 9796684 0 0 0 0 1409 2479 0 0 100 0 0
0 0 0 5535172 3424 9803384 0 0 7260 4 1677 2689 0 0 100 0 0
0 0 0 5532544 3680 9803264 0 0 560 0 1982 3131 0 0 99 0 0
0 0 0 5532296 3824 9803708 0 0 148 0 1260 2280 0 0 100 0 0
其中vmstat N
代表每隔N秒更新一次数据。
> sync //先将内存刷出,避免数据丢失
> echo 1 > /proc/sys/vm/drop_caches //释放pagecache
> echo 2 > /proc/sys/vm/drop_caches //释放dentry和inode
> echo 3 > /proc/sys/vm/drop_caches //释放pagecache、dentry和inode
实际项目中的经验告诉我们,如果因为是应用有像内存泄露、溢出的问题,从swap的使用情况是可以比较快速可以判断的,但free上面反而比较难查看。如何是核心那么就可以快速清空buffer
或cache
,但核心并没有这样做(默认值是0),我们不应该随便去改变它。
通常情况下,应用在系统上稳定运行了,free值也会保持在一个稳定值的,虽然看上去可能比较小。当发生内存不足、应用获取不到可用内存、OOM错误等问题时,还是更应该去分析应用方面的原因,如用户量太大导致内存不足、发生应用内存溢出等情况,否则,清空buffer,强制腾出free的大小,可能只是把问题给暂时屏蔽了,所以说一般情况下linux都不用经常手动释放内存。