Linux 内存获取方法详解

在 Linux 系统中,获取内存信息是一项常见且重要的任务。无论是系统监控、性能调优还是故障排查,都需要准确获取内存使用情况。本文将详细介绍 Linux 中获取内存信息的各种方法,从命令行工具到编程接口,全面覆盖不同场景的需求。

图片[1]_Linux 内存获取方法详解_知途无界

1. 文件系统接口

Linux 内核通过虚拟文件系统接口暴露内存信息,这是最直接和权威的数据来源。

1.1 /proc/meminfo – 最全面的内存信息

/proc/meminfo 是获取内存信息最重要的文件,包含了系统内存的详细统计。

# 查看完整的内存信息
cat /proc/meminfo

# 实时监控内存变化(每2秒刷新一次)
watch -n 2 'cat /proc/meminfo | head -20'

关键字段解析:

$ cat /proc/meminfo
MemTotal:       16302048 kB    # 总物理内存
MemFree:         2345678 kB    # 完全空闲内存
MemAvailable:    8567432 kB    # 可用内存(估算可立即分配给进程的内存)
Buffers:          345678 kB    # 块设备缓冲区
Cached:         4567890 kB    # 页缓存(文件内容缓存)
SwapTotal:      2097148 kB    # 交换分区总大小
SwapFree:       2097148 kB    # 空闲交换空间
Shmem:           123456 kB    # 共享内存(包括tmpfs)
Slab:            567890 kB    # Slab分配器使用的内存
Committed_AS:   12345678 kB    # 已承诺给进程的内存总量
VmallocUsed:      123456 kB    # vmalloc使用的内存

实用脚本示例:

#!/bin/bash
# 获取内存使用摘要

get_memory_info() {
    local mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
    local mem_free=$(grep MemFree /proc/meminfo | awk '{print $2}')
    local mem_available=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
    local buffers=$(grep Buffers /proc/meminfo | awk '{print $2}')
    local cached=$(grep Cached /proc/meminfo | awk '{print $2}')
    local swap_total=$(grep SwapTotal /proc/meminfo | awk '{print $2}')
    local swap_free=$(grep SwapFree /proc/meminfo | awk '{print $2}')
    
    local mem_used=$((mem_total - mem_free))
    local mem_usage_percent=$((mem_used * 100 / mem_total))
    local swap_used=$((swap_total - swap_free))
    local swap_usage_percent=0
    if [ $swap_total -gt 0 ]; then
        swap_usage_percent=$((swap_used * 100 / swap_total))
    fi
    
    echo "=== Memory Usage Summary ==="
    echo "Total RAM:    $((mem_total/1024)) MB"
    echo "Used RAM:     $((mem_used/1024)) MB ($mem_usage_percent%)"
    echo "Available:    $((mem_available/1024)) MB"
    echo "Buffers/Cache: $(((buffers + cached)/1024)) MB"
    echo "Swap Total:   $((swap_total/1024)) MB"
    echo "Swap Used:    $((swap_used/1024)) MB ($swap_usage_percent%)"
    echo "==========================="
}

get_memory_info

1.2 /proc//status – 进程内存信息

查看特定进程的内存使用情况:

# 查看当前shell进程的内存信息
cat /proc/$$/status | grep -i mem

# 查看指定PID进程的内存信息
cat /proc/1234/status | grep -i mem

# 查看所有进程的内存信息(按内存使用排序)
ps aux --sort=-%mem | head -10

关键字段:

VmSize:   123456 kB    # 虚拟内存大小
VmLck:         0 kB    # 锁定的内存大小
VmRSS:     12345 kB    # 驻留集大小(实际使用的物理内存)
VmData:    67890 kB    # 数据段大小
VmStk:       132 kB    # 栈大小
VmExe:      1234 kB    # 可执行代码大小
VmLib:     12345 kB    # 共享库大小
VmPTE:       456 kB    # 页表项大小

1.3 /proc//maps – 进程内存映射

查看进程的内存地址空间分布:

# 查看当前进程的内存映射
cat /proc/$$/maps

# 查看指定进程的内存映射(更详细的格式)
pmap -XX $$  # 当前shell
pmap -XX 1234  # 指定PID

1.4 /sys/devices/system/memory/ – sysfs 接口

sysfs 提供了更结构化的内存信息:

# 查看内存块信息
ls /sys/devices/system/memory/
cat /sys/devices/system/memory/block_size_bytes

# 查看每个内存块的在线状态
cat /sys/devices/system/memory/*/state

# 查看NUMA节点信息
ls /sys/devices/system/node/
numactl --hardware  # 更友好的NUMA信息展示

2. 命令行工具

2.1 free – 快速内存概览

# 基本用法
free
free -h  # 人类可读格式
free -m  # MB为单位
free -g  # GB为单位

# 示例输出
$ free -h
              total        used        free      shared  buff/cache   available
Mem:           15Gi       3.2Gi       1.8Gi       345Mi        10Gi        11Gi
Swap:          2.0Gi          0B       2.0Gi

输出字段说明:

  • total: 总内存
  • used: 已使用内存(不包含buffers/cache)
  • free: 完全空闲内存
  • shared: 共享内存
  • buff/cache: 缓冲区和缓存
  • available: 估算的可用内存

2.2 top/htop – 实时进程内存监控

# 使用top
top
# 按内存使用排序:Shift+M
# 显示完整命令行:c
# 退出:q

# 使用htop(需要安装)
htop
# F6 选择排序字段(PERCENT_MEM)
# F5 切换树状视图

2.3 vmstat – 虚拟内存统计

# 基本用法
vmstat
vmstat 2 5  # 每2秒采样,共5次

# 详细内存统计
vmstat -s  # 显示内存相关的统计信息
vmstat -a  # 显示活跃和非活跃内存

# 示例输出
$ vmstat -s
     16302048 K total memory
      3291456 K used memory
      1234567 K active memory
      2345678 K inactive memory
      8567432 K free memory
       345678 K buffer memory
      4567890 K swap cache

2.4 sar – 系统活动报告

# 安装sysstat包(包含sar)
sudo apt install sysstat  # Debian/Ubuntu
sudo yum install sysstat  # RHEL/CentOS

# 查看内存历史数据
sar -r
sar -r -f /var/log/sa/sa28  # 查看指定日期的数据

# 实时监控
sar -r 2 5  # 每2秒采样,共5次

# 查看内存分页统计
sar -B

2.5 ps – 进程内存快照

# 查看内存使用最高的进程
ps aux --sort=-%mem | head -10

# 自定义输出格式
ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head -10

# 查看特定用户的进程内存使用
ps -u username --sort=-%mem

# 查看线程内存使用
ps -eLf --sort=-sz

3. 编程接口

3.1 C语言接口

使用 /proc/meminfo

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    unsigned long total;
    unsigned long free;
    unsigned long available;
    unsigned long buffers;
    unsigned long cached;
    unsigned long swap_total;
    unsigned long swap_free;
} memory_info_t;

int parse_meminfo(memory_info_t *mem_info) {
    FILE *fp = fopen("/proc/meminfo", "r");
    if (!fp) {
        perror("Failed to open /proc/meminfo");
        return -1;
    }
    
    char line[256];
    while (fgets(line, sizeof(line), fp)) {
        unsigned long value;
        char key[64];
        
        if (sscanf(line, "%63[^:]: %lu", key, &value) == 2) {
            if (strcmp(key, "MemTotal") == 0) {
                mem_info->total = value;
            } else if (strcmp(key, "MemFree") == 0) {
                mem_info->free = value;
            } else if (strcmp(key, "MemAvailable") == 0) {
                mem_info->available = value;
            } else if (strcmp(key, "Buffers") == 0) {
                mem_info->buffers = value;
            } else if (strcmp(key, "Cached") == 0) {
                mem_info->cached = value;
            } else if (strcmp(key, "SwapTotal") == 0) {
                mem_info->swap_total = value;
            } else if (strcmp(key, "SwapFree") == 0) {
                mem_info->swap_free = value;
            }
        }
    }
    
    fclose(fp);
    return 0;
}

void print_memory_info(const memory_info_t *mem_info) {
    printf("Memory Information:\n");
    printf("  Total:     %lu kB (%.2f MB)\n", 
           mem_info->total, mem_info->total / 1024.0);
    printf("  Free:      %lu kB (%.2f MB)\n", 
           mem_info->free, mem_info->free / 1024.0);
    printf("  Available: %lu kB (%.2f MB)\n", 
           mem_info->available, mem_info->available / 1024.0);
    printf("  Buffers:   %lu kB (%.2f MB)\n", 
           mem_info->buffers, mem_info->buffers / 1024.0);
    printf("  Cached:    %lu kB (%.2f MB)\n", 
           mem_info->cached, mem_info->cached / 1024.0);
    
    unsigned long used = mem_info->total - mem_info->free;
    double usage_percent = (double)used / mem_info->total * 100;
    printf("  Used:      %lu kB (%.2f MB) %.1f%%\n", 
           used, used / 1024.0, usage_percent);
    
    if (mem_info->swap_total > 0) {
        unsigned long swap_used = mem_info->swap_total - mem_info->swap_free;
        double swap_percent = (double)swap_used / mem_info->swap_total * 100;
        printf("  Swap:      %lu kB used / %lu kB total (%.1f%%)\n", 
               swap_used, mem_info->swap_total, swap_percent);
    }
}

int main() {
    memory_info_t mem_info;
    
    if (parse_meminfo(&mem_info) == 0) {
        print_memory_info(&mem_info);
    }
    
    return 0;
}

使用 sysinfo 系统调用

#include <stdio.h>
#include <stdlib.h>
#include <sys/sysinfo.h>

void print_sysinfo_memory() {
    struct sysinfo info;
    
    if (sysinfo(&info) != 0) {
        perror("sysinfo failed");
        return;
    }
    
    printf("System Information (sysinfo):\n");
    printf("  Total RAM:    %lu MB\n", info.totalram / 1024 / 1024);
    printf("  Free RAM:     %lu MB\n", info.freeram / 1024 / 1024);
    printf("  Shared RAM:   %lu MB\n", info.sharedram / 1024 / 1024);
    printf("  Buffer RAM:   %lu MB\n", info.bufferram / 1024 / 1024);
    printf("  Total Swap:   %lu MB\n", info.totalswap / 1024 / 1024);
    printf("  Free Swap:    %lu MB\n", info.freeswap / 1024 / 1024);
    printf("  Number of processes: %d\n", info.procs);
}

int main() {
    print_sysinfo_memory();
    return 0;
}

3.2 Python 接口

使用 psutil 库(推荐)

import psutil
import datetime

def get_memory_info():
    """获取系统内存信息"""
    memory = psutil.virtual_memory()
    swap = psutil.swap_memory()
    
    print("=" * 50)
    print("Memory Information")
    print("=" * 50)
    print(f"Total:     {memory.total / (1024**3):.2f} GB")
    print(f"Available: {memory.available / (1024**3):.2f} GB")
    print(f"Used:      {memory.used / (1024**3):.2f} GB ({memory.percent}%)")
    print(f"Free:      {memory.free / (1024**3):.2f} GB")
    print(f"Buffers:   {memory.buffers / (1024**2):.2f} MB")
    print(f"Cached:    {memory.cached / (1024**2):.2f} MB")
    print()
    print(f"Swap Total: {swap.total / (1024**3):.2f} GB")
    print(f"Swap Used:  {swap.used / (1024**3):.2f} GB ({swap.percent}%)")
    print(f"Swap Free:  {swap.free / (1024**3):.2f} GB")

def get_process_memory(pid=None):
    """获取进程内存信息"""
    if pid is None:
        pid = os.getpid()
    
    try:
        process = psutil.Process(pid)
        mem_info = process.memory_info()
        mem_percent = process.memory_percent()
        
        print(f"\nProcess {pid} Memory Info:")
        print(f"  RSS:        {mem_info.rss / (1024**2):.2f} MB")  # Resident Set Size
        print(f"  VMS:        {mem_info.vms / (1024**2):.2f} MB")  # Virtual Memory Size
        print(f"  USS:        {process.memory_full_info().uss / (1024**2):.2f} MB")  # Unique Set Size
        print(f"  PSS:        {process.memory_full_info().pss / (1024**2):.2f} MB")  # Proportional Set Size
        print(f"  Memory %:   {mem_percent:.1f}%")
        
    except psutil.NoSuchProcess:
        print(f"Process {pid} not found")

def monitor_memory(interval=1, duration=60):
    """监控内存使用情况"""
    print(f"Monitoring memory for {duration} seconds (interval: {interval}s)")
    print("Press Ctrl+C to stop\n")
    
    start_time = datetime.datetime.now()
    end_time = start_time + datetime.timedelta(seconds=duration)
    
    try:
        while datetime.datetime.now() < end_time:
            memory = psutil.virtual_memory()
            swap = psutil.swap_memory()
            
            timestamp = datetime.datetime.now().strftime("%H:%M:%S")
            print(f"[{timestamp}] "
                  f"RAM: {memory.percent:5.1f}% ({memory.used/(1024**3):.1f}/{memory.total/(1024**3):.1f} GB) "
                  f"SWAP: {swap.percent:5.1f}%")
            
            import time
            time.sleep(interval)
            
    except KeyboardInterrupt:
        print("\nMonitoring stopped by user")

if __name__ == "__main__":
    import os
    
    get_memory_info()
    get_process_memory()
    monitor_memory(interval=2, duration=10)

直接解析 /proc/meminfo

def parse_proc_meminfo():
    """直接解析 /proc/meminfo"""
    mem_info = {}
    
    with open('/proc/meminfo', 'r') as f:
        for line in f:
            if ':' in line:
                key, value = line.split(':', 1)
                # 移除单位 kB,转换为整数
                value = value.strip().split()[0]
                mem_info[key] = int(value)
    
    return mem_info

# 使用示例
mem_info = parse_proc_meminfo()
print(f"MemTotal: {mem_info['MemTotal'] / 1024:.2f} MB")
print(f"MemAvailable: {mem_info['MemAvailable'] / 1024:.2f} MB")

3.3 其他编程语言示例

Go 语言示例

package main

import (
    "fmt"
    "io/ioutil"
    "strconv"
    "strings"
)

type MemoryInfo struct {
    Total     uint64
    Free      uint64
    Available uint64
    Buffers   uint64
    Cached    uint64
    SwapTotal uint64
    SwapFree  uint64
}

func readUintFromFile(path string) (uint64, error) {
    data, err := ioutil.ReadFile(path)
    if err != nil {
        return 0, err
    }
    
    content := strings.TrimSpace(string(data))
    // 移除 kB 单位
    if strings.HasSuffix(content, " kB") {
        content = content[:len(content)-3]
    }
    
    value, err := strconv.ParseUint(content, 10, 64)
    if err != nil {
        return 0, err
    }
    
    return value, nil
}

func getMemoryInfo() (*MemoryInfo, error) {
    info := &MemoryInfo{}
    
    var err error
    info.Total, err = readUintFromFile("/proc/meminfo")
    if err != nil {
        return nil, err
    }
    // 跳过 MemFree,继续读取其他字段...
    
    // 实际应用中需要读取所有相关字段
    // 这里简化处理
    info.Free, _ = readUintFromFile("/proc/meminfo") // 实际需要分别读取
    
    return info, nil
}

func main() {
    info, err := getMemoryInfo()
    if err != nil {
        fmt.Printf("Error reading memory info: %v\n", err)
        return
    }
    
    fmt.Printf("Total Memory: %d kB\n", info.Total)
}

4. 高级监控与可视化

4.1 使用 collectd 进行长期监控

# 安装collectd
sudo apt install collectd

# 配置collectd监控内存
echo '
LoadPlugin memory
<Plugin memory>
    ValuesPercentage false
</Plugin>
' | sudo tee -a /etc/collectd/collectd.conf

# 重启服务
sudo systemctl restart collectd

4.2 使用 Grafana + Prometheus 可视化

# prometheus.yml 配置
scrape_configs:
  - job_name: 'node'
    static_configs:
      - targets: ['localhost:9100']
# 使用 node_exporter 暴露系统指标
./node_exporter

# 在Prometheus中查询内存使用率
# (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100

4.3 自定义监控脚本

#!/bin/bash
# memory_monitor.sh - 综合内存监控脚本

LOG_FILE="/var/log/memory_monitor.log"
THRESHOLD=90  # 内存使用率阈值

log_message() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}

check_memory_usage() {
    local mem_usage=$(free | grep Mem | awk '{printf "%.1f", $3/$2 * 100.0}')
    local mem_usage_int=${mem_usage%.*}
    
    log_message "Memory Usage: ${mem_usage}%"
    
    if [ $mem_usage_int -gt $THRESHOLD ]; then
        log_message "WARNING: Memory usage exceeds threshold ($THRESHOLD%)!"
        
        # 找出内存使用最高的进程
        log_message "Top memory consuming processes:"
        ps aux --sort=-%mem | head -5 | tee -a $LOG_FILE
        
        # 可以在这里添加告警逻辑(邮件、短信等)
        # send_alert "High memory usage: ${mem_usage}%"
    fi
}

# 主循环
while true; do
    check_memory_usage
    sleep 60  # 每分钟检查一次
done

5. 性能调优与故障排查

5.1 内存泄漏检测

# 使用 valgrind 检测内存泄漏
valgrind --leak-check=full ./your_program

# 使用 pmap 监控进程内存增长
pmap -x <pid> | tail -n 1

# 定期记录进程内存使用
while true; do
    ps -p <pid> -o pid,rss,vsz,comm
    sleep 10
done

5.2 OOM(Out Of Memory)分析

# 查看OOM日志
dmesg | grep -i "out of memory"
journalctl -k | grep -i "oom"

# 查看OOM killer杀死的进程
grep -i "killed process" /var/log/syslog

# 调整OOM得分(谨慎使用)
echo -1000 > /proc/<pid>/oom_score_adj

5.3 缓存优化

# 清理页面缓存(需要root权限)
sync  # 先将缓存数据写入磁盘
echo 1 > /proc/sys/vm/drop_caches  # 清理页面缓存
echo 2 > /proc/sys/vm/drop_caches  # 清理目录项和inode缓存
echo 3 > /proc/sys/vm/drop_caches  # 清理所有缓存

# 调整swappiness(默认60,降低可减少swap使用)
echo 'vm.swappiness=10' >> /etc/sysctl.conf
sysctl -p

6. 总结与最佳实践

6.1 方法选择指南

场景推荐方法理由
快速查看内存概览free -h简洁明了,信息足够
详细内存分析cat /proc/meminfo最全面、最权威的数据
实时进程监控htop交互式界面,信息丰富
历史数据分析sar长期趋势分析
编程获取/proc/meminfo 或 sysinfo()灵活可控
跨平台开发psutil (Python)统一API,支持多平台

6.2 关键要点

  1. 理解内存指标​:区分 freeavailablebuff/cache 的含义
  2. 选择合适工具​:根据需求选择命令行工具或编程接口
  3. 注意权限​:某些信息需要 root 权限才能获取
  4. 定期监控​:建立长期监控机制,及早发现问题
  5. 结合上下文​:内存使用高不一定代表有问题,需结合应用特性分析

6.3 实用技巧

  • 使用 watch 命令实时监控变化
  • 结合 grepawk 提取关键信息
  • 建立基线数据,便于异常检测
  • 关注 MemAvailable 而非 MemFree 来判断内存压力
  • 定期检查 OOM 日志,预防系统崩溃

通过掌握这些方法,你可以全面了解 Linux 系统的内存状况,为系统优化和故障排查提供有力支持。

© 版权声明
THE END
喜欢就点个赞,支持一下吧!
点赞44 分享
评论 抢沙发
头像
欢迎您留下评论!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容