1. free

Linux内存管理是个非常复杂的问题,至少我目前是这样认为的。对于内存分配方式,内存管理方式,内存的虚拟地址、物理地址、逻辑地址、线性地址的换算方式,Linux内核如何初始化并合理使用内存的等等.....这些内容应该80%的人不想了解也不需要了解。如果你是20%的大神,请移步他处。

这篇文章总结不会很深入,这和笔者目前的能力和精力有关。以后我到了20%的人群中时,再总结有深度的内容。

一般用户了解Linux内存的使用情况常用的工具是free命令,如下:

[root@localhost ~]#free -m
             total       used       free     shared    buffers     cached
Mem:         64292      42619      21673          0       1071      38819
-/+ buffers/cache:       2728      61564
Swap:         2039          0       2039

free命令理解之后对整个Linux内存管理与分配方式会有一个大致的了解,因此我们就从free命令入手。

1.1.1. 第二行的Mem行数据:

Mem:         64292      42619      21673          0       1071      38819
  • total:总内存大小 示例总可用的内存大小是64292M。即物理内存减去一些预留位和内核的二进制代码大小。内存条故障离线这里可以看出大概,具体哪根故障可以使用dmidecode命令。

  • used:已经使用的内存 示例已使用的内存是42619M。这里使用的内存是操作系统已经分配出去的内存,包括操作系统内核和应用程序占用内存、共享内存、buffer、cache等。就是说这部分内存已经在使用中了,有些是可以回收释放的。

  • free:空闲内存 示例空闲内存是21673M。这部分内存操作已经统计到了,但是由于整个系统不需要那么多的资源,这些内存就空闲下来。

  • shared:共享内存使用情况 The shared memory column should be ignored; it is obsolete.

  • buffers:Buffer Cache内存 示例Buffer Cache大小1071M。 浅显的讲,Buffers Cache是操作系统为了加快读取外设磁盘数据占用的缓存空间大小。

  • cached:Page Cache内存 示例Page Cache大小38819M。同样浅显,Page Cache是操作系统为了加快数据写入外设磁盘占用的缓存空间大小。当内存不足时,Buffer和Cache大多数情况下是能够回收的,但也有无法回收的情况,无法回收情况请看大神文章:Linux内存中的Cache真的能被回收么?

1.1.2. 第三行的-/+ buffers/cache:

-/+ buffers/cache:       2728      61564

这一行表示减去或加上buffers和cache后used和free的大小。free命令输出对齐方式就是你看到的(大神估计看不懂这句话)。

  • used 示例 [- buffers/cache] used是2728M。是应用程序和操作系统实际使用的内存大小。不包含buffer和cache,因为这两个是为了加快读写速度临时拿来做缓存的,内存不足时可以回收。计算方法是用free输出第一行mem的数据(used-buffer-cache)。

  • free 示例 [+ buffers/cache] free是61564M。这是实际可用的内存。理由同上。计算方法是free输出第一行mem的数据(free+buffer+cache)。

1.1.3. 第四行的Swap:

Swap:  2039  0  2039

swap交换空间是为了在内存不足时可以临时作为内存扩展的一个硬盘上的空间。在使用swap时,操作系统相当于操作外设硬盘,这样会产生一定IO,而且会影响系统性能。当交换空间used不为0时,就表明系统曾经有过内存严重不足的情况,这是就要考虑加大内存,或者优化程序。

好吧,到这里看上去好像只是在讲解free命令,但我想大部分人对Linux的内存使用有一个简单的了解了。在很多Linux服务器上运行free 命令,会发现剩余内存(Mem:行的free列)很少,但实际服务器上的进程并没有占用很大的内存。这是因为Linux特殊的内存管理机制。Linux内核会把空闲的内存用作buffer/cached,用于提高文件读取性能。当应用程序需要用到内存时,buffer/cached内存是可以马上回收的。所以,对应用程序来说,buffer/cached是可用的,可用内存应该是free+buffers+cached。因为这个原因,free命令也才有第三行的-/+ buffers/cache。

如果不满足简单使用free命令了解系统内存使用情况,可以继续看下面的内容。

free只是一个命令工具,他的数据是从哪里来的呢?其实free、top等一些查看整体系统内存使用情况的工具都是通过/proc/meminfo获取的。top、ps查看单个进程内存使用情况是通过/proc/PID/status、stat、smaps文件获取的。

/proc/目录是Linux的虚拟文件系统,能时时反应系统运行的状况,刷新频率很高,好像一般是1/100秒吧,具体怎么获取这个忘了,知道的可以告诉我。而且其中的很多值都是记录开机到当前的累加值,因此很多工具通过读取proc中的文件内数据一段时间内变化来求一些平均值。

2. /proc/meminfo

cat /proc/meminfo 
MemTotal:       65835948 kB   可用总内存,对应free的total
MemFree:        22199648 kB   空闲内存,对应free的free
Buffers:         1097668 kB   Buffers缓存,对应free的Buffers
Cached:         39761112 kB   Cached缓存,对应free的Cached
SwapCached:            0 kB   Swap交换文件占用的大小,对应free的swap行used
Active:         24035520 kB
Inactive:       17231376 kB
Active(anon):     367136 kB
Inactive(anon):    57040 kB
Active(file):   23668384 kB
Inactive(file): 17174336 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:       2088952 kB   交换空间总大小,对应free的swap行total
SwapFree:        2088952 kB   交换空间剩余,对于free的swap的free
Dirty:                52 kB   等待被写回到磁盘的内存大小
Writeback:             0 kB   正在被写回到磁盘的内存大小
AnonPages:        408180 kB   未映射页的内存大小
Mapped:            29732 kB   设备和文件等映射的大小
Shmem:             16060 kB   共享内存大小
Slab:            2139048 kB   内核数据结构缓存的大小,可以减少申请和释放内存带来的消耗slabtop查看
SReclaimable:    2003812 kB   可收回Slab的大小
SUnreclaim:       135236 kB   不可收回Slab的大小
KernelStack:        7664 kB
PageTables:        40372 kB   管理内存分页页面的索引表的大小
NFS_Unstable:          0 kB   不稳定页表的大小
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:    35006924 kB
Committed_AS:    1456732 kB
VmallocTotal:   34359738367 kB可以vmalloc虚拟内存大小
VmallocUsed:      389788 kB   已经被使用的虚拟内存大小
VmallocChunk:   34324938288 kB
HardwareCorrupted:     0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:        1216 kB
DirectMap2M:     2086912 kB
DirectMap1G:    65011712 kB

对于/proc/meminfo项的一些细节方面,我只了解一些。比如: MemTotal是实际可用内存的总大小, 即物理内存减去一些预留位和内核的二进制代码大小。

这里有些内容也是在网上查的,这里也算学习并记录一下。还有一些不能确定的就不误导大家了。

或许你还想了解单个进程的内存使用情况,我只能告诉你这个/proc/pid/{stat,status,smaps}文件有关,你可以了解一下这个文件参数的含义。

好吧,到这里其实已经了解这篇文章的大概了。后面的涉及到内核源码和逻辑,我也是试着学习分析,有不足之处还请扶正。

3. ./kernel/fs/proc/meminfo.c

我们之所能在/proc/meminfo中看到那么多的内容,是因为meminfo.c文件对此进行了定义。

static int meminfo_proc_show(struct seq_file *m, void *v)

就是这个函数将信息输出到/proc/meminfo文件中,内核在运行时会定期刷新/proc内容。

下面从proc_meminfo模块初始化来简单分析一下,本次使用的内核是kernel3.10。

module_init(proc_meminfo_init);

系统模块初始化,这里初始化的是proc_meminfo模块。Linux系统模块化的设计使许多功能能够独立开来,在需要时进行加载。

static int __init proc_meminfo_init(void)
{
    proc_create("meminfo", 0, NULL, &meminfo_proc_fops);
    return 0;
}

这里meminfo_proc_fops是一个file_operations的结构体。

static const struct file_operations meminfo_proc_fops = {
    .open        = meminfo_proc_open,
    .read        = seq_read,
    .llseek      = seq_lseek,
    .release     = single_release,
};

这里4个值是4个系统函数,其中meminfo_proc_open函数主要用来打开meminfo文件,他的功能就是返回single_open。

static int meminfo_proc_open(struct inode *inode, struct file *file)
{
    return single_open(file, meminfo_proc_show, NULL);
}

而在single_open中调用了meminfo_proc_show函数,将内容输出到/proc/meminfo文件中

static int meminfo_proc_show(struct seq_file *m, void *v)
{
    struct sysinfo i;
    unsigned long committed;
    unsigned long allowed;
    struct vmalloc_info vmi;
    long cached;
    unsigned long pages[NR_LRU_LISTS];
    int lru;

/*
 * display in kilobytes.
 */
#define K(x) ((x) << (PAGE_SHIFT - 10))
    si_meminfo(&i);
    si_swapinfo(&i);
    committed = percpu_counter_read_positive(&vm_committed_as);
    allowed = ((totalram_pages - hugetlb_total_pages())
        * sysctl_overcommit_ratio / 100) + total_swap_pages;

    cached = global_page_state(NR_FILE_PAGES) -
            total_swapcache_pages() - i.bufferram;
    if (cached < 0)
        cached = 0;

    get_vmalloc_info(&vmi);

    for (lru = LRU_BASE; lru < NR_LRU_LISTS; lru++)
        pages[lru] = global_page_state(NR_LRU_BASE + lru);

    /*
     * Tagged format, for easy grepping and expansion.
     */
    seq_printf(m,
        "MemTotal:       %8lu kB\n"
        "MemFree:        %8lu kB\n"
        "Buffers:        %8lu kB\n"
        "Cached:         %8lu kB\n"
        "SwapCached:     %8lu kB\n"
        "Active:         %8lu kB\n"
        "Inactive:       %8lu kB\n"
        "Active(anon):   %8lu kB\n"
        "Inactive(anon): %8lu kB\n"
        "Active(file):   %8lu kB\n"
        "Inactive(file): %8lu kB\n"
        "Unevictable:    %8lu kB\n"
        "Mlocked:        %8lu kB\n"
#ifdef CONFIG_HIGHMEM
        "HighTotal:      %8lu kB\n"
        "HighFree:       %8lu kB\n"
        "LowTotal:       %8lu kB\n"
        "LowFree:        %8lu kB\n"
#endif
#ifndef CONFIG_MMU
        "MmapCopy:       %8lu kB\n"
#endif
        "SwapTotal:      %8lu kB\n"
        "SwapFree:       %8lu kB\n"
        "Dirty:          %8lu kB\n"
        "Writeback:      %8lu kB\n"
        "AnonPages:      %8lu kB\n"
        "Mapped:         %8lu kB\n"
        "Shmem:          %8lu kB\n"
        "Slab:           %8lu kB\n"
        "SReclaimable:   %8lu kB\n"
        "SUnreclaim:     %8lu kB\n"
        "KernelStack:    %8lu kB\n"
        "PageTables:     %8lu kB\n"
#ifdef CONFIG_QUICKLIST
        "Quicklists:     %8lu kB\n"
#endif
        "NFS_Unstable:   %8lu kB\n"
        "Bounce:         %8lu kB\n"
        "WritebackTmp:   %8lu kB\n"
        "CommitLimit:    %8lu kB\n"
        "Committed_AS:   %8lu kB\n"
        "VmallocTotal:   %8lu kB\n"
        "VmallocUsed:    %8lu kB\n"
        "VmallocChunk:   %8lu kB\n"
#ifdef CONFIG_MEMORY_FAILURE
        "HardwareCorrupted: %5lu kB\n"
#endif
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
        "AnonHugePages:  %8lu kB\n"
#endif
        ,
        K(i.totalram),
        K(i.freeram),
        K(i.bufferram),
        K(cached),
        K(total_swapcache_pages()),
        K(pages[LRU_ACTIVE_ANON]   + pages[LRU_ACTIVE_FILE]),
        K(pages[LRU_INACTIVE_ANON] + pages[LRU_INACTIVE_FILE]),
        K(pages[LRU_ACTIVE_ANON]),
        K(pages[LRU_INACTIVE_ANON]),
        K(pages[LRU_ACTIVE_FILE]),
        K(pages[LRU_INACTIVE_FILE]),
        K(pages[LRU_UNEVICTABLE]),
        K(global_page_state(NR_MLOCK)),
#ifdef CONFIG_HIGHMEM
        K(i.totalhigh),
        K(i.freehigh),
        K(i.totalram-i.totalhigh),
        K(i.freeram-i.freehigh),
#endif
#ifndef CONFIG_MMU
        K((unsigned long) atomic_long_read(&mmap_pages_allocated)),
#endif
        K(i.totalswap),
        K(i.freeswap),
        K(global_page_state(NR_FILE_DIRTY)),
        K(global_page_state(NR_WRITEBACK)),
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
        K(global_page_state(NR_ANON_PAGES)
          + global_page_state(NR_ANON_TRANSPARENT_HUGEPAGES) *
          HPAGE_PMD_NR),
#else
        K(global_page_state(NR_ANON_PAGES)),
#endif
        K(global_page_state(NR_FILE_MAPPED)),
        K(global_page_state(NR_SHMEM)),
        K(global_page_state(NR_SLAB_RECLAIMABLE) +
                global_page_state(NR_SLAB_UNRECLAIMABLE)),
        K(global_page_state(NR_SLAB_RECLAIMABLE)),
        K(global_page_state(NR_SLAB_UNRECLAIMABLE)),
        global_page_state(NR_KERNEL_STACK) * THREAD_SIZE / 1024,
        K(global_page_state(NR_PAGETABLE)),
#ifdef CONFIG_QUICKLIST
        K(quicklist_total_size()),
#endif
        K(global_page_state(NR_UNSTABLE_NFS)),
        K(global_page_state(NR_BOUNCE)),
        K(global_page_state(NR_WRITEBACK_TEMP)),
        K(allowed),
        K(committed),
        (unsigned long)VMALLOC_TOTAL >> 10,
        vmi.used >> 10,
        vmi.largest_chunk >> 10
#ifdef CONFIG_MEMORY_FAILURE
        ,atomic_long_read(&num_poisoned_pages) << (PAGE_SHIFT - 10)
#endif
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
        ,K(global_page_state(NR_ANON_TRANSPARENT_HUGEPAGES) *
           HPAGE_PMD_NR)
#endif
        );

    hugetlb_report_meminfo(m);

    arch_report_meminfo(m);

    return 0;
#undef K
}

感觉在内核分析这块太浅显了,只是停留在表面的函数调用,每个函数的功能还不能明确了解。庞大的Linux Kernel就是由这样一个个模块组成,一步一个脚印的行走,希望这篇文章对我有所成长,对大家有所帮助。

4. 参阅

http://km.oa.com/group/568/articles/show/199326 http://km.oa.com/group/657/articles/show/262561?kmref=search&from_page=1&no=9&is_from_iso=1 http://km.oa.com/group/799/articles/show/144637?kmref=search&from_page=1&no=6&is_from_iso=1 http://blog.chinaunix.net/uid-16974460-id-1729258.html

Copyright © 温玉 2021 | 浙ICP备2020032454号 all right reserved,powered by Gitbook该文件修订时间: 2023-06-19 08:59:50

results matching ""

    No results matching ""