計算 Linux 內存使用率方法及C實現



通過獲取Linux中的 /proc/stat 文件中的內容可以獲取系統內存的詳細信息:

# cat /proc/meminfo 
MemTotal:        3880404 kB
MemFree:         3182248 kB
MemAvailable:    3396580 kB
Buffers:           39588 kB
Cached:           355616 kB
SwapCached:            0 kB
Active:           318708 kB
Inactive:         252380 kB
Active(anon):     176120 kB
Inactive(anon):      248 kB
Active(file):     142588 kB
Inactive(file):   252132 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:        175940 kB
Mapped:            54184 kB
Shmem:               488 kB
Slab:              62040 kB
SReclaimable:      48712 kB
SUnreclaim:        13328 kB
KernelStack:        2672 kB
PageTables:         6080 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     1940200 kB
Committed_AS:     615340 kB
VmallocTotal:   34359738367 kB
VmallocUsed:       14160 kB
VmallocChunk:   34359715580 kB
HardwareCorrupted:     0 kB
AnonHugePages:     36864 kB
CmaTotal:              0 kB
CmaFree:               0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:       53120 kB
DirectMap2M:     3092480 kB
DirectMap1G:     3145728 kB

各字段含義見下表:

指標 作用
MemTotal 總內存大小
MemFree 空閑內存大小
buffers/cached 磁盤緩存的大小
MemAvailable 可用內存大小
SwapTotal 可用的swap空間的總的大小。
SwapFree 剩余swap空間的大小。
Dirty 需要寫入磁盤的內存區大小。
Writeback 正在被寫回磁盤的大小。
AnonPages 未映射頁的內存大小。
Mapped 設備和文件等映射的大小。
Slab 內核數據結構slab的大小,可以減少申請和釋放內存帶來的消耗。

注Buffers 和 Cached的區別

Buffers 是指用來給塊設備做的緩沖大小,他只記錄文件系統的metadata以及 tracking in-flight pages. cached 是用來給文件做緩沖。

buffers 是值存儲目錄里面有什么內容,權限等等。 而cached直接用來記憶我們打開的文件,比如先后執行兩次命令#man X ,你就可以明顯的感覺到第二次的開打的速度快很多。 而buffers隨時都在增加,比如先后兩次使用ls /dev后,就會發現第二次執行的速度會較第一次快。 這就是buffers/chached的區別。

  • 以內核態來講, buffers  和 cached  是已經被使用的,可用內存就是 MemAvailable
MemUsed  = MemTotal - MemFree
  • 以用戶態來講,buffers  和 cached  可被分配。
free = MemFree + Buffers + Cahched
  • 本着監控應用對物理內存使用情況的目的采集,計算方法:
MemUsedPrec = 100*(MemTotal - MemFree - Buffers - Cahched)/MemTotal

黑洞

    經過一番計算,發現
/proc/meminfo 中的數據無論如何無法與 free 中的內容對應,尤其是在 used 部分。經過一番信息檢索,得出一個結論, free 命令中的數值是按照 /proc/meminfo 中的數據,根據一定算法計算所得,並且新版舊版的 free 所輸出內容也不一致。因此按照 proc/meminfo 中的數據計算內存使用率是更加精確的。
進一步探索,會發現 Linux 存在一個內存黑洞,在某博主博客找到如下描述:

追蹤Linux系統的內存使用一直是個難題,很多人試着把能想到的各種內存消耗都加在一起,kernel text、kernel modules、buffer、cache、slab、page table、process RSS…等等,卻總是與物理內存的大小對不上,這是為什么呢?因為Linux kernel並沒有滴水不漏地統計所有的內存分配,kernel動態分配的內存中就有一部分沒有計入/proc/meminfo中。
—— 《/PROC/MEMINFO之謎

綜上原因,計算Linux內存使用率也就沒有必要去細扣每個數值的含義了,大致了解如下內容即可:

  • MemTotal:總內存大小
  • MemFree: 空閑內存大小
  • buffers/cached: 磁盤緩存的大小
  • MemAvailable: 可用內存大小

而計算內存使用率只需按照這個方法計算:

實際可挪用的內存數: free+cache+buffer,
實際可使用的內存數: used-cache-buffer (total-free-cache-buffer)。
內存占用率:(total-available) / total * 100

C實現

同樣的, 先定義一個結構體用於存放相關數據:

struct MEM_INFO
{
    unsigned int total;
    unsigned int free;
    unsigned int buffers;
    unsigned int cached;
    unsigned int swap_cached;
    unsigned int swap_total;
    unsigned int swap_free;
    unsigned int available;
};
typedef struct MEM_INFO Mem_info;

之后定義函數,用於獲取及計算內存數據:

void  get_mem_occupy (Mem_info *o)
{
    FILE* fpMemInfo = fopen("/proc/meminfo", "r");
    if (NULL == fpMemInfo)
    {
        return ;
    }
    int i = 0;
    int value;
    char name[1024];
    char line[1024];
    int nFiledNumber = 2;
    int nMemberNumber = 5;
    while (fgets(line, sizeof(line) - 1, fpMemInfo))
    {
        if (sscanf(line, "%s%u", name, &value) != nFiledNumber)
        {
            continue;
        }
        if (0 == strcmp(name, "MemTotal:"))
        {
            ++i;
            o->total = value;
        }
        else if (0 == strcmp(name, "MemFree:"))
        {
            ++i;
            o->free = value;
        }
        else if (0 == strcmp(name, "MemAvailable:"))
        {
            ++i;
            o->available = value;
        }
        else if (0 == strcmp(name, "Buffers:"))
        {
            ++i;
            o->buffers = value;
        }
        else if (0 == strcmp(name, "Cached:"))
        {
            ++i;
            o->cached = value;
        }
        if (i == nMemberNumber)
        {
            break;
        }
    }
    // system("free");
    // system("cat /proc/meminfo");
    // printf("MemTotal      : %d\n",o->total);
    // printf("MemFree       : %d\n",o->free);
    // printf("MemAvailable  : %d\n",o->available);
    // printf("MemBuffers    : %d\n",o->buffers);
    // printf("MemCached     : %d\n",o->cached);
    // printf("MemSwapCached : %d\n",o->swap_cached);
    // printf("MemSwapTotal  : %d\n",o->swap_total);
    // printf("MemSwapFree   : %d\n",o->swap_free);
    fclose(fpMemInfo);
}

float cal_mem_occupy(Mem_info *o)
{
    return (100.0 * (o->total - o->available) / o->total);
}

最后調用即可:

Mem_info omem;
    while(1)
    {
        // printf("-------------------- Mem occupy -------------------\n");
        get_mem_occupy(&omem);
        printf("Mem Usage(%): %8.4f\n", cal_mem_occupy(&omem));
        printf("\n");
    }

參考文獻


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM