xiaobaoqiu Blog

Think More, Code Less

Linux Memory Usage

1.问题

这段时间最易个图片迁移的工作,涉及60W+图片的迁移,用java写的临时代码,部署到图片服务器上。因为服务器还有其他服务,看日志的同时,也再看迁移的应用对服务器CPU和内存使用的影响。使用top命令猛然发现Mem的used狂涨而free狂降,下面是两个时刻的top情况:

1
2
3
4
5
6
7
8
9
10
11
top - 15:41:56 up 176 days, 19:46,  2 users,  load average: 0.34, 0.32, 0.28
Tasks: 521 total,   1 running, 520 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.1%us,  0.1%sy,  0.0%ni, 98.6%id,  1.2%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:  66057208k total, 57548808k used,  8508400k free,  1154764k buffers
Swap: 50331640k total,        0k used, 50331640k free, 47054444k cached

top - 15:43:45 up 176 days, 19:48,  2 users,  load average: 0.25, 0.30, 0.27
Tasks: 521 total,   1 running, 520 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.2%us,  0.0%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:  66057208k total, 57941160k used,  8116048k free,  1154764k buffers
Swap: 50331640k total,        0k used, 50331640k free, 47448656k cached

2.疑惑

第一想法是内存泄漏了,之前写惯C++代码Windows下碰到过一次明显的内存泄漏,情况和这个完全类似。

但是这个是java代码,java想写出内存泄漏的代码不容易。

3.原因

问了个老鸟,原因是Linux的内存管理和Windows不一样。在Linux下,无论物理内存有多大都将其充份利用,会将应用程序调用过的硬盘数据保留在内存,利用内存读写的高速特性来提高Linux系统的数据访问性能。

3.1 linux中内存是如何使用

当有应用需要读写磁盘数据时,由系统把相关数据从磁盘读取到内存,如果物理内存不够,则把内存中的部分数据导入到磁盘,从而把磁盘的部分空间当作虚拟内存来使用,也称为Swap。如果给所有应用分配足够内存后,物理内存还有剩余,linux会尽量再利用这些空闲内存,以提高整体I/O效率,其方法是把这部分剩余内存再划分为cache及buffer两部分加以利用。

从磁盘读取到内存的数据在被相关应用程序读取后,如果有剩余内存,则这部分数据会存入cache,以备第2次读取时,避免重新读取磁盘。当一个应用程序在内存中修改过数据后,因为写入磁盘速度相对较低,在有空闲内存的情况下,这些数据先存入buffer,在以后某个时间再写入磁盘,从而应用程序可以继续后面的操作,而不必等待这些数据写入磁盘的操作完成。

如果在某个时刻,系统需要更多的内存,则会把cache部分擦除,并把buffer中的内容写入磁盘,从而把这两部分内存释放给系统使用,这样再次读取cache中的内容时,就需要重新从磁盘读取了。

通过以上分析可以得知,Mem中的空闲物理内存(free)不多,不一定表示系统运行状态很差,因为内存的cache及buffer部分可以随时被重用,在某种意义上,这两部分内存也可以看作是额外的空闲内存。

4.Linux和Windows内存管理的差异

无论物理内存有多大,Linux都将其充份利用,将一些程序调用过的硬盘数据读入内存,利用内存读写的高速特性来提高Linux系统的数据访问性能。

而Windows 是只在需要内存时,才为应用程序分配内存,并不能充分利用大容量的内存空间。

换句话说,每增加一些物理内存,Linux 都将能充分利用起来,发挥了硬件投资带来的好处,而Windows只将其做为摆设,即使增加8GB甚至更大。

5.什么是Linux的cache,buffers,Swap

Cached表示page cache大小,Buffers表示内存中块I/O缓冲(buffer cache)的大小。通常而言,Cached很关键,Buffers则影响不大。

简单来说,磁盘的操作有逻辑级(文件系统)和物理级(磁盘块),page cache对应的就是用来缓存逻辑级数据,buffer cache用来缓存物理级数据。

假设我们通过文件系统操作文件,那么文件将被缓存到Page Cache,如果需要刷新文件的时候,page cache将交给buffer cache去完成,因为buffer cache就是缓存磁盘块的。 也就是说,直接去操作文件,那就是page cache区缓存,用dd等命令直接操作磁盘块,就是buffer cache缓存的东西。

5.1 buffer

buffer是作为buffer cache的内存,是块设备的读写缓冲区。

buffer cache也叫块缓冲,由物理内存分配,是对物理磁盘上的一个磁盘块(磁盘的组织单位)进行的缓冲。

设立buffer cache的目的是为在程序多次访问同一磁盘块时,减少访问时间。系统将磁盘块首先读入buffer cache,如果cache空间不够时,会通过一定的策略将一些过时或多次未被访问的buffer cache清空。程序在下一次访问磁盘时首先查看是否在buffer cache找到所需块,命中可减少访问磁盘时间,不命中时需重新读入buffer cache。

对buffer cache 的写分为两种,一是直接写,这是程序在写buffer cache后也写磁盘,要读时从buffer cache 上读,二是后台写,程序在写完buffer cache 后并不立即写磁盘,因为有可能程序在很短时间内又需要写文件,如果直接写,就需多次写磁盘了,这样效率很低,而是过一段时间后由后台写(批量写),减少了多次访磁盘的时间。

buffer cache 是由物理内存分配,linux系统为提高内存使用率,会将空闲内存全分给buffer cache ,当其他程序需要更多内存时,系统会减少cahce大小。

5.2 cache

cache是page cache的内存, 文件系统的cache。

page cache也叫页缓冲或文件缓冲,文件读取是由外存上不连续的几个磁盘块,到buffer cache,然后组成page cache,然后供给应用程序。

page cache在linux读写文件时,它用于缓存文件的逻辑内容,从而加快对磁盘上映像和数据的访问。具体说是加速对文件内容的访问,buffer cache缓存文件的具体内容——物理磁盘上的磁盘块,这是加速对磁盘的访问。

5.3 Swap

swap space交换空间,是虚拟内存的表现形式。系统为了应付一些需要大量内存的应用,而将磁盘上的空间做内存使用,当物理内存不够用时,将其中一些暂时不需的数据交换到交换空间。

做虚拟内存的好处是让进程以为好像可以访问整个系统物理内存。因为在一个进程访问数据时,其他进程的数据会被交换到交换空间中。

6.Linux内存常用命令

6.1 top

1
2
3
4
5
6
7
8
9
top - 16:13:52 up 1 day,  6:01, 16 users,  load average: 2.89, 2.27, 2.14
Tasks: 274 total,   7 running, 266 sleeping,   0 stopped,   1 zombie
%Cpu(s): 44.3 us, 16.6 sy,  0.0 ni, 38.4 id,  0.6 wa,  0.0 hi,  0.1 si,  0.0 st
KiB Mem:   8047584 total,  7905356 used,   142228 free,    73476 buffers
KiB Swap: 15879164 total,    26872 used, 15852292 free,  1962736 cached

PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND
29121 xiaobaoq  20   0 3938m 2.1g 2.1g S  34.2 27.7 119:28.33 VirtualBox
2548 xiaobaoq  20   0 1371m  79m  19m R  31.2  1.0 131:40.03 compiz

字段的意义如下:

1
2
3
4
5
6
7
8
9
10
11
12
PID:进程的ID
  USER:进程所有者
  PR:进程的优先级别,越小越优先被执行
  NInice:值
  VIRT:进程占用的虚拟内存
  RES:进程占用的物理内存
  SHR:进程使用的共享内存
  S:进程的状态。S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值为负数
  %CPU:进程占用CPU的使用率
  %MEM:进程使用的物理内存和总内存的百分比
  TIME+:该进程启动后占用的总的CPU时间,即占用CPU使用时间的累加值。
  COMMAND:进程启动命令名称

top命令提供了额外的输入,常用的命令包括(注意是大写):

1
2
3
  P:按%CPU使用率排行
  T:按MITE+排行
  M:按%MEM排行

6.2 free

1
2
3
4
5
xiaobaoqiu@xiaobaoqiu:~$ free -m
             total       used       free     shared    buffers     cached
Mem:          7858       7687        171          0         71       1889
-/+ buffers/cache:       5726       2132
Swap:        15506         26      15480

-m表示单位为M,可以使用-g表示单位为G,默认为K。 -/+ buffers/cache表示物理内存的缓存统计,Used为4506,即实际使用的buffers与cache 总量,也是实际使用的内存总量;Free为3352, 即未被使用的buffers与cache和未被分配的内存之和,这就是系统当前实际可用内存。

Swap表示硬盘上交换分区的使用情况。只有mem被当前进程实际占用完,即没有了buffers和cache时,才会使用到swap。

注意一下几个关系: Free(-/+ buffers/cache行)= Free(Mem)+buffers(Mem)+Cached(Mem)

Used(Mem) = Used(-/+ buffers/cache)+ buffers(Mem) + Cached(Mem)

total(Mem) = used(-/+ buffers/cache) + free(-/+ buffers/cache)

从应用程序角度来看,对于应用程序来说,buffers/cached 是等于可用的,因为buffer/cached是为了提高文件读取的性能,当应用程序需在用到内存的时候,buffer/cached会很快地被回收。所以从应用程序的角度来说,可用内存=系统free memory+buffers+cached.

6.3 /proc/meminfo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
xiaobaoqiu@xiaobaoqiu:~$ cat /proc/meminfo
MemTotal:        8047584 kB
MemFree:          162416 kB
Buffers:           73772 kB
Cached:          1943380 kB
SwapCached:         3860 kB
Active:          3636032 kB
Inactive:        1608472 kB
Active(anon):    3092468 kB
Inactive(anon):  1121848 kB
Active(file):     543564 kB
Inactive(file):   486624 kB
Unevictable:          48 kB
Mlocked:              48 kB
SwapTotal:      15879164 kB
SwapFree:       15852292 kB
Dirty:               664 kB
Writeback:             0 kB
AnonPages:       3223572 kB
Mapped:          2597276 kB
Shmem:            986964 kB
Slab:             311976 kB
SReclaimable:     247580 kB
SUnreclaim:        64396 kB
KernelStack:        6808 kB
PageTables:        61012 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:    19902956 kB
Committed_AS:   11365592 kB
VmallocTotal:   34359738367 kB
VmallocUsed:      360776 kB
VmallocChunk:   34359367876 kB
HardwareCorrupted:     0 kB
AnonHugePages:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:       71156 kB
DirectMap2M:     8187904 kB

其中的MemTotal, MemFree, Buffers, Cached, SwapTotal, SwapFree和free命令中的值对应起来。

Cached is the size of the page cache。 Buffers is the size of in-memory block I/O buffer。

6.4 vmstat

vmstat -s显示内存使用的统计信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
xiaobaoqiu@xiaobaoqiu:~$ vmstat -s
      8047584 K total memory
      7841504 K used memory
      3624652 K active memory
      1584740 K inactive memory
       206080 K free memory
        69252 K buffer memory
      1890844 K swap cache
     15879164 K total swap
        39488 K used swap
     15839676 K free swap
      8744974 non-nice user cpu ticks
          345 nice user cpu ticks
      4309209 system cpu ticks
     29496503 idle cpu ticks
       240289 IO-wait cpu ticks
           19 IRQ cpu ticks
        14705 softirq cpu ticks
            0 stolen cpu ticks
      7878551 pages paged in
     18640168 pages paged out
          976 pages swapped in
         9899 pages swapped out
    664925325 interrupts
   1290574510 CPU context switches
   1409739162 boot time
        36758 forks

参考

  1. http://www.linuxintheshell.org/2012/06/05/episode-008-free-understanding-linux-memory-usage/