内存的管理
在内存管理上份为两层,一个是线性区,类似于 00c73000-00c88000,对应于虚拟内存,它实际上不占用实际物理内存;另外一个是具体的物理页面,它对应我们机器上的物理内存。
这里要提到一个很重要的概念,内存的延迟分配/按需分配。Linux 内核在用户申请内存的时候,只是给它分配了一个线性区(也就是虚存),并没有分配实际物理内存;只有当用户使用这块内存的时候(比如malloc后,memset一个字节),内核才会分配具体的物理页面给用户,这时候才占用宝贵的物理内存。内核释放物理页面是通过释放线性区,找到其所对应 的物理页面,将其全部释放的过程。
1.物理内存:
实际内存,常见的有8G 16G 32G 64G等
2.虚拟内存:
操作系统(windows或者linux)基于物理内存有限及内存操作效率考虑,设计了虚拟地址访问机制,能够分配比系统现有物理内存更多的内存。虚拟内存使用的是硬盘的空间,硬盘空间动辄几十G上百G,运用了虚拟内存技术,即拿出一部分硬盘空间来充当内存使用,大幅提升了“可用” 内存的大小。(实际上,CPU还是读取物理内存)。
Linux下两种主要Cache方式:Buffer Cache和Page Cache.前者Buffer Cache针对磁盘块的读写,后者Page Cache针对文件等的读写。这些Cache有效缩短了I/O系统调用(比如 read,write,getdents)的时间
两个关键概念:
2.1页面调度
页面调度是指从磁盘向内存传输数据,以及相反的过程,这个过程之所以被称为页面调度,是因为Linux内存被平均划分成大小相等的页面;通常页面大小为 4KB和8KB(在Solaris中可以用pagesize命令查看)。当可执行程序开始运行时,它的映象会一页一页地从磁盘中读入,与此类似,当某些内存在一段时间内空闲(不被使用),就可以把它们换出到交换空间中,这样就可以把空闲的RAM交给其他需要它的程序使用。
2.2交换
交换的概念容易和页面调度通混淆,页面调度是指把一个进程所占内存的空闲部分传输到磁盘上,而交换是指当系统中实际的内存已不够满足新的分配需求时,把整个进程传输到磁盘上,交换活动通常意味着内存不足。其中,交换空间是专门用于临时存储内存的一块磁盘空间,通常在页面调度和交换进程数据时使用。(linux下可配置 /proc/sys/vm/swappiness ,默认为10,也就是达到90,既可以使用swap。看睡眠情况,一般不睡眠情况下,32G物理内存以上,则推荐为8G的交换空间)
程序操作内存
系统函数brk mmap等实现的是直接操作内存,brk是通过移动最新的偏移地址得到内存(这个会存在内存空洞),而mmap是找空闲内存,而glic(ptmalloc)等运行库为了内存高效,会进行封装:其多个小128k的内存申请释放后,进行内存合并管理;大于128,用mmap进行直接操作内存,没有合并管理一说。
因此,可能存在代码free,但是虚拟内存还是占用的。
对内存空洞要求高的话,建议使用tcmalloc。
内存查看
1.top命令
【大致看下,容易有歧义,建议以free来查看内存情况】
【按(shift+M)会进行内存排序,关注下VIRT和res不要一直涨就可以了】
2.free
[root@scs-2 tmp]# free
total used free shared buffers cached
Mem: 128 119 8 0 2 22 从OS的角度来看
-/+ buffers/cache: 95 32 应用程序的内存
swap: 255 0 255
第2行-/+ buffers/cache:
-buffers/cache 的内存数: 95 (应用程序的内存,等于第1行的 used - buffers - cached)
+buffers/cache 的内存数: 32 (应用程序的内存,等于第1行的 free + buffers + cached)
可见-buffers/cache反映的是被程序实实在在吃掉的内存,而+buffers/cache反映的是可以挪用的内存总数。
第三行数据是交换分区SWAP的,也就是我们通常所说的虚拟内存。
(mem)行是从OS的角度来看,因为对于OS,buffers/cached 都是属于被使用。
used 119 已用内存中包括内核(OS)使用+Application(X, oracle,等)使用的+buffers+cached.
3.一个进程的内存
我们通过free命令查看机器空闲内存时,会发现free的值很小。这主要是因为,在Linux系统中有这么一种思想,内存不用白不用,因此它尽可能的cache和buffer一些数据,以方便下次使用。但实际上这些内存也是可以立刻拿来使用的。
所以 空闲内存=free+buffers+cached=total-used
内存泄漏
1.依据
查看一个进程使用的内存,是一个很令人困惑的事情。因为我们写的程序,必然要用到动态链接库,将其加入到自己的地址空间中,但是 / proc/pid/statm 统计出来的数据,会将这些动态链接库所占用的内存也简单的算进来。
这样带来的问题,动态链接库占用的内存有些是其他程序使用时占用的,却算在了你这里。你的程序中包含了子进程,那么有些动态链接库重用的内存会被重复计算。
怀疑某处发生了内存泄露,可以查看该进程的maps表,看进程的堆段或者mmap段的虚拟地址空间是否持续增加,如果是,说明很可能发生了内存泄露,如果mmap段虚拟地址空间持续增加,还可以看到各个段的虚拟地址空间的大小,从而可以确定是申请了多大的内存,对调试内存泄露类问题可以起到很好的定位作用。Rss-Resident Set Size 实际使用物理内存(包含共享库占用的内存)
学习链接
https://www.jianshu.com/p/38a4bcf564d5 内存机制,包括示例内存释放
https://www.cnblogs.com/yangykaifa/p/7397497.html mtrace 定位泄漏
https://testerhome.com/articles/20547 gdb定位泄漏