Linux proc文件系统 内存影射

文章目录

常见的内存分配函数

  • malloc / calloc / realloc(来自 C 标准库)

    void *malloc(size_t size):分配 size 字节的内存。
    void *calloc(size_t nmemb, size_t size):分配并初始化为0的内存,大小为 nmemb * size。
    void *realloc(void *ptr, size_t size):重新分配一块内存。
    释放函数:
    void free(void *ptr):释放由 malloc/calloc/realloc 分配的内存。

  • mmap / munmap(Linux 系统调用级别)

    void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset):用于分配匿名内存或映射文件。
    int munmap(void *addr, size_t length):释放 mmap 分配的内存。
    常用于共享内存、匿名内存区域的分配,灵活性更高。

    // 使用 mmap 分配匿名内存
    size_t size = 4096; // 分配 1 页(通常 4KB)大小的内存
    void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE,
    MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);

    if (addr == MAP_FAILED) {
    perror("mmap failed");
    return 1;
    }

/proc/pid/ 目录解析

  • /proc/<pid>/maps : 内存映射区域概览 【程序地址空间】

    该文件列出进程的每个虚拟内存区域的信息,包括地址、权限、偏移、设备、inode 以及映射的文件(如有)。
    <起始地址>-<结束地址> <权限> <偏移> <设备号> <inode> <路径>

    如图,是从上到下为低地址向高地址的程序地址空间。

  • 2./proc/<pid>/status ------ 进程状态摘要(含内存使用情况)

    提供当前进程的状态、资源使用、权限、线程数等,常用于查看内存大小的总体信息。

    VmPeak: 132456 kB 使用过的最大虚拟内存
    VmSize: 130000 kB 当前分配的虚拟内存
    VmRSS: 20480 kB 常驻内存集(实际占用物理内存)
    VmData: 90000 kB 数据段使用内存
    VmStk: 136 kB 栈区大小
    VmExe: 1024 kB 代码段大小
    VmLib: 16384 kB 进程加载的 共享库(Shared Library) 占用的虚拟内存大小

  • 3./proc/<pid>/smaps ------ maps 的详细版(精细统计每段内存)
    该文件扩展了 maps 的内容,为每个内存段提供详细内存使用信息,如共享、私有的内存、页的大小等。

    7f0c5f000000-7f0c5f021000 rw-p 00000000 00:00 0
    Size: 132 kB 区域大小
    Rss: 20 kB 实际驻留物理内存
    Pss: 10 kB 平均共享内存
    Shared_Clean: 0 kB 被多个进程共享的页面
    Shared_Dirty: 0 kB
    Private_Clean: 0 kB 私有页面
    Private_Dirty: 20 kB
    Referenced: 20 kB 被访问过的内存
    Anonymous: 20 kB 匿名映射(如 malloc 分配的内存)
    ...

用户进程的内存空间分配算法

  1. 连续分配算法

    • 定义:为进程分配一个连续的内存区域,进程的所有数据和代码都存放在该连续空间中。

    • 典型算法:

      单一连续分配:整个内存仅分配给一个进程(早期单任务系统)。

      固定分区分配:内存划分为若干固定大小的分区,每个分区装入一个进程。

      动态分区分配:根据进程需求动态划分内存,如首次适应、最佳适应算法。【连续分配算法】

      • 首次适应算法(First Fit):从空闲分区链的起始位置开始扫描,找到第一个大小足够满足请求的空闲分区,将其分割后分配给进程。
      • 最佳适应算法(Best Fit):遍历整个空闲分区链,找到大小最接近请求且不小于请求的空闲分区进行分配。(实际上碎片化问题更严重)
    • 特点:实现简单,但内存碎片问题严重,空间利用率低。

  2. 离散分配算法

    • 定义:将进程拆分为多个部分,分配到不连续的内存块中,通过地址映射机制(如页表、段表)实现逻辑地址到物理地址的转换。
    • 典型算法:
      分页存储管理:进程划分为固定大小的页(Page),内存划分为页框(Frame),页与页框一一对应。
      分段存储管理:进程划分为逻辑上独立的段(Segment),如代码段、数据段,各段分配独立的内存区域。
      段页式存储管理:结合分段和分页,先分段再分页。
    • 特点:有效解决内存碎片问题,支持虚拟内存,是现代操作系统的主流方案。

现代操作系统(如 Linux、Windows)对用户进程的内存管理采用基于分页的虚拟内存机制,属于离散分配算法的范畴,但实现细节更为复杂。

mmap 分配大内存可能不在堆中

小内存分配(通常小于 128KB)

通过 堆(Heap) 分配,使用 brk 系统调用扩展进程的堆空间,内存区域在 /proc/pid/maps 中标记为 [heap]。

大内存分配(通常大于等于 128KB)

通过 匿名映射(Anonymous Mapping) 分配,使用 mmap 系统调用在虚拟地址空间中创建独立的内存区域,这类区域在 /proc/pid/maps 中标记为 rw-p 00000000 00:00 0(无文件关联的匿名映射),不属于传统堆或共享区。

编写程序,连续申请分配六个128MB空间(记为1~6号),然后释放第2、3、5号的128MB空间。然后再分配1024MB,再分配64M内存,观察 /proc/pid/maps, 【解释说明用户进程空间分配属于课本中的离散还是连续分配算法?首次适应还是最佳适应算法?用户空间存在碎片问题吗?】

代码:

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>

#define ALLOC_MB(x) ((x) * 1024 * 1024)

void *alloc_region(size_t size) {
    void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (ptr == MAP_FAILED) {
        perror("mmap");
        exit(1);
    }
    return ptr;
}

void print_hint(const char *msg) {
    printf("\n==== %s ====\n", msg);
    printf("pid = %d,请查看 /proc/%d/maps\n", getpid(), getpid());
    printf("按 Enter 继续...\n");
    getchar();
}

int main() {
    void *blocks[6];

    // 分配六块 128MB 匿名内存
    for (int i = 0; i < 6; i++) {
        blocks[i] = alloc_region(ALLOC_MB(128));
        memset(blocks[i], 0, 1);  // 确保内存实际分配
    }

    print_hint("已分配 6 块 128MB");

    // 释放第 2、3、5 块
    munmap(blocks[1], ALLOC_MB(128));
    munmap(blocks[2], ALLOC_MB(128));
    munmap(blocks[4], ALLOC_MB(128));

    print_hint("已释放第 2、3、5 块");

    // 分配 1024MB
    void *big = alloc_region(ALLOC_MB(1024));
    memset(big, 0, 1);

    print_hint("已分配 1024MB");

    // 再分配 64MB
    void *extra = alloc_region(ALLOC_MB(64));
    memset(extra, 0, 1);

    print_hint("已分配额外的 64MB");

    sleep(60);
    return 0;
}
  • 分配 6 个 128MB 内存块:

    heap\]下一行的 7fc8c95d8000-7fc8f95d8000 即为分配的6个128MB内存块 0x7fc8f95d8000 - 0x7fc8c95d8000 = 0x30000000 = 768MB **mmap 分配的大块内存,不在 \[heap\] 上!**

    heap\]下这三段: 7fc8c95d8000-7fc8d15d8000 rw-p ... 7fc8d95d8000-7fc8e15d8000 rw-p ... 7fc8f15d8000-7fc8f95d8000 rw-p ... 刚好是 128\*3 = 384 MB. 地址连续但 有缺口,说明确实释放了中间段

    7fc8c95d8000-7fc8d15d8000 变为 7fc8895d8000-7fc8d15d8000 这是分配了1024MB内存

    0x7fc8d15d8000 - 0x7fc8895d8000 = 0x48000000 = 1207959552 bytes = 1152 MB

  • 额外分配一个 64MB 内存块:

    7fc8f15d80000-7fc8f95d80000 变为了7fc8ed5d8000-7fc8f95d8000

    = 0x7fc8f95d8000 - 0x7fc8ed5d8000

    = 0x080000000 (十六进制)

    = 128MB + 64MB = 192MB malloc 的 64MB 被放入了这块扩展后的区域中。

换为 malloc 现象相同
复制代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define ALLOC_MB(x) ((x) * 1024 * 1024)

void *alloc_region(size_t size) {
    void *ptr = malloc(size);
    if (ptr == NULL) {
        perror("malloc");
        exit(1);
    }
    return ptr;
}

void free_region(void *ptr, size_t size) {
    free(ptr);
}

void print_hint(const char *msg) {
    printf("\n==== %s ====\n", msg);
    printf("pid = %d,请查看 /proc/%d/maps\n", getpid(), getpid());
    printf("按 Enter 继续...\n");
    getchar();
}

int main() {
    void *blocks[6];

    getchar();

    // 分配六块 128MB 内存
    for (int i = 0; i < 6; i++) {
        blocks[i] = alloc_region(ALLOC_MB(128));
        memset(blocks[i], 0, 1);  // 确保内存实际分配
    }

    print_hint("已分配 6 块 128MB");

    // 释放第 2、3、5 块
    free_region(blocks[1], ALLOC_MB(128));
    free_region(blocks[2], ALLOC_MB(128));
    free_region(blocks[4], ALLOC_MB(128));

    print_hint("已释放第 2、3、5 块");

    // 分配 1024MB
    void *big = alloc_region(ALLOC_MB(1024));
    memset(big, 0, 1);

    print_hint("已分配 1024MB");

    // 再分配 64MB
    void *extra = alloc_region(ALLOC_MB(64));
    memset(extra, 0, 1);

    print_hint("已分配额外的 64MB");

    sleep(60);
    return 0;
}    

起始:

复制代码
5635d3a68000-5635d3a69000 r--p 00000000 08:05 655630                     /home/wyx/work/SZU_OS/ex3/memtest2.out
5635d3a69000-5635d3a6a000 r-xp 00001000 08:05 655630                     /home/wyx/work/SZU_OS/ex3/memtest2.out
5635d3a6a000-5635d3a6b000 r--p 00002000 08:05 655630                     /home/wyx/work/SZU_OS/ex3/memtest2.out
5635d3a6b000-5635d3a6c000 r--p 00002000 08:05 655630                     /home/wyx/work/SZU_OS/ex3/memtest2.out
5635d3a6c000-5635d3a6d000 rw-p 00003000 08:05 655630                     /home/wyx/work/SZU_OS/ex3/memtest2.out
5635d3fcf000-5635d3ff0000 rw-p 00000000 00:00 0                          [heap]
7fa337f61000-7fa337f83000 r--p 00000000 08:05 1050757                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7fa337f83000-7fa3380fb000 r-xp 00022000 08:05 1050757                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7fa3380fb000-7fa338149000 r--p 0019a000 08:05 1050757                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7fa338149000-7fa33814d000 r--p 001e7000 08:05 1050757                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7fa33814d000-7fa33814f000 rw-p 001eb000 08:05 1050757                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7fa33814f000-7fa338155000 rw-p 00000000 00:00 0 
7fa338168000-7fa338169000 r--p 00000000 08:05 1050743                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7fa338169000-7fa33818c000 r-xp 00001000 08:05 1050743                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7fa33818c000-7fa338194000 r--p 00024000 08:05 1050743                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7fa338195000-7fa338196000 r--p 0002c000 08:05 1050743                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7fa338196000-7fa338197000 rw-p 0002d000 08:05 1050743                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7fa338197000-7fa338198000 rw-p 00000000 00:00 0 
7ffe3d307000-7ffe3d328000 rw-p 00000000 00:00 0                          [stack]
7ffe3d3f1000-7ffe3d3f5000 r--p 00000000 00:00 0                          [vvar]
7ffe3d3f5000-7ffe3d3f7000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]

分配 6 块 128MB: 发现也不在堆中

复制代码
5635d3a68000-5635d3a69000 r--p 00000000 08:05 655630                     /home/wyx/work/SZU_OS/ex3/memtest2.out
5635d3a69000-5635d3a6a000 r-xp 00001000 08:05 655630                     /home/wyx/work/SZU_OS/ex3/memtest2.out
5635d3a6a000-5635d3a6b000 r--p 00002000 08:05 655630                     /home/wyx/work/SZU_OS/ex3/memtest2.out
5635d3a6b000-5635d3a6c000 r--p 00002000 08:05 655630                     /home/wyx/work/SZU_OS/ex3/memtest2.out
5635d3a6c000-5635d3a6d000 rw-p 00003000 08:05 655630                     /home/wyx/work/SZU_OS/ex3/memtest2.out
5635d3fcf000-5635d3ff0000 rw-p 00000000 00:00 0                          [heap]
7fa307f5b000-7fa337f61000 rw-p 00000000 00:00 0 
7fa337f61000-7fa337f83000 r--p 00000000 08:05 1050757                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7fa337f83000-7fa3380fb000 r-xp 00022000 08:05 1050757                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7fa3380fb000-7fa338149000 r--p 0019a000 08:05 1050757                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7fa338149000-7fa33814d000 r--p 001e7000 08:05 1050757                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7fa33814d000-7fa33814f000 rw-p 001eb000 08:05 1050757                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7fa33814f000-7fa338155000 rw-p 00000000 00:00 0 
7fa338168000-7fa338169000 r--p 00000000 08:05 1050743                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7fa338169000-7fa33818c000 r-xp 00001000 08:05 1050743                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7fa33818c000-7fa338194000 r--p 00024000 08:05 1050743                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7fa338195000-7fa338196000 r--p 0002c000 08:05 1050743                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7fa338196000-7fa338197000 rw-p 0002d000 08:05 1050743                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7fa338197000-7fa338198000 rw-p 00000000 00:00 0 
7ffe3d307000-7ffe3d328000 rw-p 00000000 00:00 0                          [stack]
7ffe3d3f1000-7ffe3d3f5000 r--p 00000000 00:00 0                          [vvar]
7ffe3d3f5000-7ffe3d3f7000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]

释放第 2、3、5 块后现象相同:

复制代码
5635d3a68000-5635d3a69000 r--p 00000000 08:05 655630                     /home/wyx/work/SZU_OS/ex3/memtest2.out
5635d3a69000-5635d3a6a000 r-xp 00001000 08:05 655630                     /home/wyx/work/SZU_OS/ex3/memtest2.out
5635d3a6a000-5635d3a6b000 r--p 00002000 08:05 655630                     /home/wyx/work/SZU_OS/ex3/memtest2.out
5635d3a6b000-5635d3a6c000 r--p 00002000 08:05 655630                     /home/wyx/work/SZU_OS/ex3/memtest2.out
5635d3a6c000-5635d3a6d000 rw-p 00003000 08:05 655630                     /home/wyx/work/SZU_OS/ex3/memtest2.out
5635d3fcf000-5635d3ff0000 rw-p 00000000 00:00 0                          [heap]
7fa307f5b000-7fa30ff5c000 rw-p 00000000 00:00 0 
7fa317f5d000-7fa31ff5e000 rw-p 00000000 00:00 0 
7fa32ff60000-7fa337f61000 rw-p 00000000 00:00 0 
7fa337f61000-7fa337f83000 r--p 00000000 08:05 1050757                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7fa337f83000-7fa3380fb000 r-xp 00022000 08:05 1050757                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7fa3380fb000-7fa338149000 r--p 0019a000 08:05 1050757                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7fa338149000-7fa33814d000 r--p 001e7000 08:05 1050757                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7fa33814d000-7fa33814f000 rw-p 001eb000 08:05 1050757                    /usr/lib/x86_64-linux-gnu/libc-2.31.so
7fa33814f000-7fa338155000 rw-p 00000000 00:00 0 
7fa338168000-7fa338169000 r--p 00000000 08:05 1050743                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7fa338169000-7fa33818c000 r-xp 00001000 08:05 1050743                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7fa33818c000-7fa338194000 r--p 00024000 08:05 1050743                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7fa338195000-7fa338196000 r--p 0002c000 08:05 1050743                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7fa338196000-7fa338197000 rw-p 0002d000 08:05 1050743                    /usr/lib/x86_64-linux-gnu/ld-2.31.so
7fa338197000-7fa338198000 rw-p 00000000 00:00 0 
7ffe3d307000-7ffe3d328000 rw-p 00000000 00:00 0                          [stack]
7ffe3d3f1000-7ffe3d3f5000 r--p 00000000 00:00 0                          [vvar]
7ffe3d3f5000-7ffe3d3f7000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
相关推荐
tokepson10 小时前
Mysql下载部署方法备份(Windows/Linux)
linux·服务器·windows·mysql
zz_nj12 小时前
工作的环境
linux·运维·服务器
极客先躯13 小时前
如何自动提取Git指定时间段的修改文件?Win/Linux双平台解决方案
linux·git·elasticsearch
suijishengchengde14 小时前
****LINUX时间同步配置*****
linux·运维
qiuqyue14 小时前
基于虹软Linux Pro SDK的多路RTSP流并发接入、解码与帧级处理实践
linux·运维·网络
切糕师学AI14 小时前
Linux 操作系统简介
linux
南烟斋..15 小时前
GDB调试核心指南
linux·服务器
爱跑马的程序员15 小时前
Linux 如何查看文件夹的大小(du、df、ls、find)
linux·运维·ubuntu
oMcLin17 小时前
如何在 Ubuntu 22.04 LTS 上部署并优化 Magento 电商平台,提升高并发请求的响应速度与稳定性?
linux·运维·ubuntu
Qinti_mm17 小时前
Linux io_uring:高性能异步I/O革命
linux·i/o·io_uring