系统性能分析-内存

内存分配与回收

malloc()C标准库提供的内存分配函数,对应到系统调用上,有两种实现方式,及brk()mmap()

对小块内存(小于128K)C标准库使用brk()来分配,也就是通过移动堆顶的位置来分配内存,这些内存释放后并不会立刻归还给系统,而是被缓存起来,这样就可以重复使用。

而大块内存(大于128K),则直接使用mmap()来分配,也就是直接在文件映射段找一块内存分配出去。

这两种方式,各有优缺点。

brk()方式的缓存,可以减少缺页异常的发生,提高内存访问效率,不过这些内存由于没有归还系统,在内存工作繁忙时,频繁的内存分配和释放会造成内存碎片。

mmap()方式分配的内存,会在内存释放时归还给系统,所以mmap()方式会发生缺页异常,在内存工作繁忙时,频繁的内存分配会导致大量的缺页异常,使内核的管理负担增大。这也是malloc只对大内存块使用mmap()的原因。了解了这两种调用方式后,还需要了解清楚,当这两种调用发生后,其实并没有真正分配内存。这些内存都只在首次访问时才分配,也就是通过缺页异常进入内核,再由内核来分配内存。

整体来说,Linux使用伙伴系统来管理内存分配。前面提到,这些内存在MMU中以页为单位进行管理,伙伴系统也一样,以页为单位来管理内存,并且会通过相临页的合并,来减少内存碎片(比如brk方式产生的碎片)

如果遇到比页更小的对象,比如不到1K的时候,怎么分配内存?

在用户空间,malloc()通过brk()分配内存,在释放时并不马上归还系统,而是缓存起来重复利用。在内核空间,Linux通过slab分配器来管理小内存。

对内存来说,若是只分配而不释放,则会造成内存泄露,甚至会耗尽系统内存。所以应用程序用完内存后,还需要调用free()或者unmap(),来释放这些内存资源。当然系统也不会让某个应用程序用完系统内存,发现内存资源紧张时,系统会通过一系列机制来回收内存,如下三种方式:

1、回收缓存:比如使用LRU(Last Recently Used)算法,回收最近使用较少的页面。

2、回收不常访问内存,把不常访问内存通过交换分区写入磁盘中。

3、杀死进程,内存紧张时系统会通过OOM(Out Of Memory),直接杀死占用大量内存的进程。

其中第二种方式用到swapswap其实就是把一块磁盘空间当内存使用,它可以把进程暂时不用的数据存储到磁盘中(这个过程称为换出),当进程访问这些数据时,再从磁盘读入内存中(这个过程称为换入)。所以可以看到swap把内存扩大了,要注意只有内存不够时,才会发生swap交换,而且磁盘的读写速度比内存慢,会导致内存的性能问题。

第三种提到OOM,它其实是内核的一种保护机制。它监控进程的内存使用情况,并使用oom_score为每个进程的内存使用进行评分:

一个进程消耗的内存越大,oom_score就越大

一个进程运行占用的CPU越多,oom_score就越小

这样进程的oom_score就越大,消耗的内存就越多,也就越容易被OOM杀死,从而更好的保护系统。当然,实际工作需要时,管理员也可以通过/proc文件系统,手动设置进程的oom_adj,从而调整进程的oom_scoreoom_adj的范围为[-17,15],数值越大,越容易被OOM杀死,数值越小,越不容易被OOM杀死,其中-17表示禁止OOM

比如使用下面的命令,就可以把sshd进程的oom_adj调为-16,这样,sshd进程就不容易被OOM杀死。

echo -16 >/proc/$(pidof sshd)/oom_adj

proc文件系统

/procLinux内核提供的一种特殊的文件系统,系统用户和内核交互的接口。比方说,用户可以从/proc中查询内核的运行状态和配置选项,查询进程的运行状态、统计数据等,也可以通过/proc来修改内核的配置。/proc文件系统也是很多性能工具的最终数据来源。比如free,就是通过读取/proc/meminfo,获得内存使用情况。通过man free

Buffers

memory used by kernel buffers (Buffers in /proc/meminfo)

cache  

memory used by the page cache and slabs (Cached and Slab in /proc/meminfo)

内存性能指标

首先是系统内存使用情况,比如已用内存、剩余内存、共享内存、可用内存、缓存和缓冲区的用量等

*已用内存和剩余内存就是已经使用和还未使用的内存

*共享内存是通过tmpfs系统实现的,所以它的大小就是tmpfs使用的内存大小,tmpfs其实也是一种特殊的缓存。

*可用内存是新进程可以使用的最大内存,它包括剩余内存和可回收缓存

*缓存包括两部分,一部分是从磁盘读取文件的页缓存,用来缓存从磁盘读取的数据,可以加快再次访问的速度;另一部分是slab分配器中的可回收内存

*缓冲区是对原始磁盘块的临时存储,用来缓存将要写入磁盘的数据。方便内核把分散的写集中起来,统一优化磁盘写入

其次是进程内存使用情况,比如进程的虚拟内存、常驻内存、共享内存以及swap内存等

*虚拟内存包括进程代码段、数据段、共享内存、已经申请的堆内存和已经换出的内存等(已经申请的内存,即使没有分配物理内存,也算作虚拟内存)

*常驻内存是进程实际使用的物理内存,不过,它不包括swap和共享内存

*swap内存,通过swap换出到磁盘的内存

这些指标中,常驻内存一般会换算成占系统总内存的百分比,也就是进程的内存使用率

在内存分配原理中说,系统调用内存分配请求后,并不会立即为其分配内存,而是在请求首次访问时,通过缺页异常来分配。缺页异常有分为以下两种情况:

*可以直接从物理内存中分配时,被称为次缺页异常

*需要磁盘I/O介入(swap)时,被称为主缺页异常

显然主缺页异常升高,就意味着需要磁盘I/O,那么内存访问也会慢很多

第三类指标是swap使用情况,比如swap的已用空间、剩余空间、换入速度、换出速度等

*已用空间和剩余空间就是已经使用和没有使用的内存空间

*换入速度和换出速度则是每秒换入和换出内存的大小

如何快速分析出内存的性能瓶颈

内存性能指标很多,但都是为了描述内存的基本原理,指标之间都有一定的关联。为了迅速定位内存问题,通常先运行几个覆盖面比较大的性能工具,比如freetopvmstatpidstat等,主要分析思路如下:

1、现用freetop查看系统内存整体使用情况

2、再用vmstatpidstat,查看一段时间的趋势,从而判断出内存问题的类型

3、最后进行详细分析,比如内存分配分析、缓存/缓冲区分析、具体进程的内存使用分析等。

猜你喜欢

转载自blog.51cto.com/13162375/2545296