博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
How Linux Works(三):内存管理
阅读量:6160 次
发布时间:2019-06-21

本文共 7297 字,大约阅读时间需要 24 分钟。

hot3.png

内存是计算机中与CPU进行沟通的桥梁,用于暂时存放CPU中的运算数据。Linux 内核的内存管理机制设计得非常精妙,对于 Linux 内核的性能有很大影响。在早期的 Unix 系统中,fork 启动新进程时,由于从父进程往子进程复制内存信息需要消耗一定的时间,因此启动多个进程时存在性能瓶颈。现在的 Linux 内核则通过“写时复制(copy-on-write)”等机制提高了创建进程的效率;也正是因为这个原因,关于 Linux 内存分配、计算、空闲判断有一些特别的地方需要注意。

内存异常: Out of Memory (OOM) Killer

$ dmesg | tail[1880957.563400] Out of memory: Kill process 18694 (perl) score 246 or sacrifice child

最常见的内存管理异常就是 Out of memory 问题。通常是因为某个应用程序大量请求内存导致系统内存不足造成的,触发 Linux 内核里的 ,OOM killer 会杀掉某个进程以释放内存留给系统内核用。它实际上算一种保护机制,不致于让系统立刻崩溃,有些壮士断腕的意思。

内核检测到内存利用不足,就会选择并杀掉某个“bad”进程。如何判断和选择一个 “bad” 进程呢? 算法和思路其实非常朴素(简单):最 bad 的那个进程就是那个占用内存最多的进程。内核源代码详见 linux/mm/oom_kill.c 。

我的内存利用率为什么特别高?

  • 内存利用率(概括): free
  • 内存利用率(进程): top

内存空闲率 = (Total - Used) / Total = (7982M - 7503M) / 7983M X 100 % = 6 %“真实的” 内存空闲率 =  (free + shared + buffers + cached)/ Total = 5860 M / 7983M X 100 % = 73.4 %

实际情况是系统运行正常、不存在内存不足的情况,对于应用程序来说,“真实的” 内存空闲率是 73.4% 。如果要回答这个问题,必须了解内存管理的基础 —— 物理地址空间和逻辑地址空间。

按照用途,内存可以划分为“内核内存”和“用户内存”(用户进程及磁盘高速缓存),包括内核本身在内,程序在访问物理内存时,并不直接指定物理地址,而是指定逻辑地址。CPU 上搭载的硬件 MMU (Memory Management Unit)会参照物理-逻辑地址对应关系表实现对映射后物理地址上的数据访问。x86 架构中逻辑地址空间限制在 4GB ,在 x86_64 架构中则没有此限制。

Linux 内存的分类

用户内存的分类有两组概念比较重要:匿名内存和File-backed内存;Active 和 Inactive 。它们的区别如下:

  • 匿名内存:用来存储用户进程计算过程中间的数据,与物理磁盘的文件没有关系;
  • File-backed内存:用作磁盘高速缓存,其物理内存与物理磁盘上的文件是对应的;
  • Active : 刚被使用过的数据的内存空间;
  • Inactive : 包含有长时间未被使用过的数据的内存空间;

Shmem(shared memory)指的就是 tmpfs 所使用的内存 —— 一个基于内存的文件系统,提供可以接近零延迟的快速存储区域。Linux 可以将空闲内存用于缓存,并且在应用程序需要的时候收回。“­/+ buffers/cache”: 提供了关于内存利用率更加准确的数值。buffers: buffer cache,用于块设备I/O ; cached: page cache, 用于文件系统。例如:

# free			  total        used        free      shared  buff/cache   availableMem:        1012720      168756       23576       52024      820388      754520Swap:        262140          88      262052# mkdir /mnt/ramdisk# mount -t tmpfs -o size=512m tmpfs /mnt/ramdisk# vi /etc/fstab# tmpfs       /mnt/ramdisk tmpfs   nodev,nosuid,noexec,nodiratime,size=1024M   0 0
  • 内存利用率(详细):cat /proc/meminfo
$ cat /proc/meminfoMemTotal:        8174352 kBMemFree:          376952 kBBuffers:          527412 kBCached:          5178924 kBSwapCached:           60 kBActive:          3061760 kBInactive:        4066588 kBActive(anon):    1112780 kBInactive(anon):   314156 kBActive(file):    1948980 kBInactive(file):  3752432 kBUnevictable:        6724 kBMlocked:            6724 kBSwapTotal:      16779884 kBSwapFree:       16777400 kBDirty:               376 kBWriteback:             0 kBAnonPages:       1428844 kBMapped:            64632 kBShmem:               644 kBSlab:             557384 kBSReclaimable:     338272 kBSUnreclaim:       219112 kBKernelStack:        4024 kBPageTables:        12440 kBNFS_Unstable:          0 kBBounce:                0 kBWritebackTmp:          0 kBCommitLimit:    20867060 kBCommitted_AS:    2406484 kBVmallocTotal:   34359738367 kBVmallocUsed:      111536 kBVmallocChunk:   34359455060 kBHugePages_Total:       0HugePages_Free:        0HugePages_Rsvd:        0HugePages_Surp:        0Hugepagesize:       2048 kBDirectMap4k:        6384 kBDirectMap2M:     2080768 kBDirectMap1G:     6291456 kB

Linux 内存的计算

各类内存的计算公式如下:

Shmem = 磁盘高速缓存(buffers/cached)- Filed-backed内存(file) = 匿名内存(anon)- AnonPages 用户内存 = Active(file) + Inactive(file) + Active(anon) + Inactive(anon) + Unevictable = buffers + cached + AnonPages

内核内存 = Memtotal - (MemFree + Active + Inactive + Unevictable)

$ cat /proc/meminfo | grep ActiveActive:          3065880 kBActive(anon):    1116748 kBActive(file):    1949132 kB-bash-4.3$-bash-4.3$-bash-4.3$ cat /proc/meminfo | grep InActive-bash-4.3$-bash-4.3$ cat /proc/meminfo | grep InactiveInactive:        4067224 kBInactive(anon):   314156 kBInactive(file):  3753068 kB-bash-4.3$-bash-4.3$-bash-4.3$ cat /proc/meminfo | grep anonActive(anon):    1120720 kBInactive(anon):   314156 kB-bash-4.3$-bash-4.3$ cat /proc/meminfo | grep fileActive(file):    1949236 kBInactive(file):  3753096 kB-bash-4.3$

Linux 进程的内存

-bash-4.3$ ps -e -o 'pid,comm,args,pcpu,rsz,vsz,stime,user,uid' | grep slview |  sort -nrk530029 java            /slview/jdk150/jdk1.5.0_06/  2.5 1337496 2678836 Dec07 slview 5432231574 bash            -bash                        0.0  2028  70592 17:08 slview   5432223398 crond           crond                        0.0  1688 102180 16:10 slview   54322 1123 crond           crond                        0.0  1688 102180 Dec10 slview   5432228252 crond           crond                        0.0  1596 102028 16:45 slview   54322

执行“ps aux” 后输出的各进程的 RSS (resident set size), 表示进程占用内存的大小,单位是KB。 需要注意的是,RSS 值实际上是基于 pmap 命令,表示“该进程正在使用的物理内存的总和”。pmap 提供了进程的内存映射,也可以支持多个进程的内存状态显示(pmap pid1 pid2 pid3)。与 ldd 命令类似,pmap 命令可以查看到程序调用的路径。如果查看一个已经运行,但是又不知道程序路径的程序,使用pmap更快捷。

$ pmap -x 3002930029:   /slview/jdk150/jdk1.5.0_06/bin/java -com.apache.TestAddress           Kbytes     RSS   Dirty Mode   Mapping0000000008048000      60      48       0 r-x--  java0000000008057000       8       8       8 rwx--  java0000000009f1d000   23184   23140   23140 rwx--    [ anon ]000000004d1f1000     108      96       0 r-x--  ld-2.5.so000000004d20c000       4       4       4 r-x--  ld-2.5.so000000004d20d000       4       4       4 rwx--  ld-2.5.so000000004d214000    1356     548       0 r-x--  libc-2.5.so000000004d367000       8       8       8 r-x--  libc-2.5.so00007f581e51d000      16      16       0 r--s-  huanan-product-2.6.1-snapshots.jar00007f581e521000      24      24       0 r--s-  dt.jar00007f581e527000      36      36       0 r--s-  gnome-java-bridge.jar00007f581e530000      32      32       8 rw-s-  1322800007f581e538000       4       4       4 rw---    [ anon ]00007f581e539000       4       4       0 r----    [ anon ]00007f581e53a000       8       8       8 rw---    [ anon ]00007fffe9eb7000      84      32      32 rw---    [ stack ]00007fffe9fff000       4       4       0 r-x--    [ anon ]ffffffffff600000       4       0       0 r-x--    [ anon ](部分省略)----------------  ------  ------  ------total kB         2484196   36180   26880

/proc/PID/status 支持的选项有:

  • VmData: data段大小
  • VmExe: text段大小
  • Vmlib: 共享库的使用量
  • VmRSS: 物理内存使用量
  • VmSwap: 交换空间的使用量
$ cat /proc/30029/statusName:	javaState:	S (sleeping)Tgid:	30029Pid:	30029PPid:	29983TracerPid:	0Uid:	54322	54322	54322	54322Gid:	54323	54323	54323	54323FDSize:	8192Groups:	10 54323VmPeak:	 2754032 kBVmSize:	 2678836 kBVmLck:	       0 kBVmHWM:	 1337912 kBVmRSS:	 1337512 kBVmData:	 2575692 kBVmStk:	    1012 kBVmExe:	      60 kBVmLib:	  101564 kBVmPTE:	    3048 kBThreads:	98SigQ:	0/63825SigPnd:	0000000000000000ShdPnd:	0000000000000000SigBlk:	0000000000000004SigIgn:	0000000000000001SigCgt:	1000000180005cceCapInh:	0000000000000000CapPrm:	0000000000000000CapEff:	0000000000000000CapBnd:	ffffffffffffffffCpus_allowed:	ffffffffCpus_allowed_list:	0-31Mems_allowed:	00000000,Mems_allowed_list:	0voluntary_ctxt_switches:	12468nonvoluntary_ctxt_switches:	19

Linux 应用内存分配

类似 Java 之类的虚拟机应用程序可以设置内存参数,例如: Xms128m JVM初始分配的堆内存 Xmx512m JVM最大允许分配的堆内存 XX:PermSize=64M JVM初始分配的非堆内存 XX:MaxPermSize=128M JVM最大允许分配的非堆内存

如果该应用需要较大的内存空间,可以调整为 -Xmx1024m、-Xmx2048m 以保障应用程序的运行性能,XX:MaxPermSize 设置过小会导致内存溢出,java.lang.OutOfMemoryError: PermGen space。但是 需要特别注意 的是:Xmx 绝对不能超过最大物理内存,或者说需要保留一定的剩余内存空间,否则将有可能导致其它进程因为没有可用内存而阻塞,甚至无法登陆机器 。

正如摔跤游戏一样,内存管理的法则就是让进程在 留有余地 的前提下搏杀。

扩展阅读:Linux 操作系统

推荐:电子书《Linux Perf Master》

发表在GitBook平台,欢迎订阅、下载、批评指正:

转载于:https://my.oschina.net/zijingshanke/blog/1590591

你可能感兴趣的文章
感恩被救赎——爱是恒久忍耐
查看>>
科技巨头开发人工智能 稀缺品种或成A股香饽饽
查看>>
1702 素数判定 2
查看>>
eva0.4.1源码看看5
查看>>
oracle 德部分操作笔记(自己用的)
查看>>
Linux第十四周
查看>>
结对项目 - 词频统计
查看>>
为什么map对象不能使用stl中的sort函数
查看>>
OnlineJudge 离线题库采集
查看>>
linux使用VNC服务轻松远程安装oracle
查看>>
转自把《编程珠玑》读薄
查看>>
oracle 11g的em界面按钮乱码的解决办法
查看>>
Linux的前世今生
查看>>
如何查看某个端口被谁占用
查看>>
一台路由器实现电信ITV与宽带共享上网
查看>>
关于raid5 5e 5ee的性能 对比及其数据恢复原理
查看>>
python从2.6升到2.7后 桌面输入法图标不见
查看>>
VTP Pruning
查看>>
企业中squid+iptables多模块的综合应用案例
查看>>
pl/sql developer导入导出
查看>>