You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Linux/Ubuntu中获取进程精确的栈与堆内存占用?

栈与堆内存占用统计方案(针对嵌入式MCU验证)

一、栈内存统计问题解决

你遇到的/proc/pid/smaps显示4KB栈占用是因为Linux内存分页机制限制,无法精准到字节级。以下几种方法可满足需求:

1. 运行时动态追踪栈使用最大值

通过记录栈底与实时栈顶的差值,统计实际运行中的栈峰值:

#include <stdint.h>
#include <stdio.h>

uintptr_t stack_bottom;
size_t max_stack_used = 0;

// 检查当前栈使用量并更新峰值
void check_stack_usage(void) {
    uint8_t stack_top;
    size_t current_used = stack_bottom - (uintptr_t)&stack_top;
    if (current_used > max_stack_used) {
        max_stack_used = current_used;
    }
}

int main(void) {
    // 初始化栈底:main函数第一个局部变量地址(栈从高地址向低地址增长,多数架构适用)
    uint8_t bottom_marker;
    stack_bottom = (uintptr_t)&bottom_marker;

    // 在程序关键节点(如复杂逻辑执行前/后、函数调用边界)调用检查
    check_stack_usage();
    // ... 业务代码

    // 程序结束时输出栈峰值
    printf("Max Stack Used: %zu bytes\n", max_stack_used);
    return 0;
}

2. 编译器静态分析栈需求

使用GCC的-fstack-usage编译选项,编译后生成.su文件,包含每个函数的静态栈使用量:

gcc -fstack-usage your_code.c -o your_program

.su文件示例内容:

your_code.c:16:6:func1  16	static
your_code.c:22:6:func2  32	static

可编写脚本汇总所有函数的栈使用量,结合调用栈深度估算整体栈上限,适合CI快速静态检查。

3. 利用RTOS自带栈监控

若MCU使用RTOS(如FreeRTOS),多数RTOS提供栈监控API,例如FreeRTOS的uxTaskGetStackHighWaterMark(),可直接获取任务栈剩余空间,计算已使用的最大值。

二、堆内存统计优化(包含释放统计)

你当前的malloc包装仅统计分配,要统计释放,可通过以下两种方式实现:

1. 包装malloc/free(侵入式)

自定义函数替换原有malloc/free,记录每个块的大小:

#include <stdlib.h>
#include <stdint.h>

size_t total_allocated = 0;
size_t total_freed = 0;
size_t current_heap_used = 0;
size_t max_heap_used = 0;

void* call_malloc(size_t size) {
    // 额外分配空间存储块大小,放在返回指针前侧
    size_t* ptr = malloc(size + sizeof(size_t));
    if (ptr == NULL) return NULL;
    *ptr = size;
    total_allocated += size;
    current_heap_used += size;
    if (current_heap_used > max_heap_used) {
        max_heap_used = current_heap_used;
    }
    return (void*)(ptr + 1);
}

void call_free(void* ptr) {
    if (ptr == NULL) return;
    // 取出前侧的大小字段
    size_t* size_ptr = (size_t*)((uint8_t*)ptr - sizeof(size_t));
    size_t size = *size_ptr;
    total_freed += size;
    current_heap_used -= size;
    free(size_ptr);
}

// 用宏替换原有malloc/free,无需修改业务代码
#define malloc(size) call_malloc(size)
#define free(ptr) call_free(ptr)

2. 使用malloc钩子(无侵入式,GCC扩展)

借助GCC的__malloc_hook和__free_hook,无需修改业务代码即可统计:

#include <stdlib.h>
#include <malloc.h>

size_t total_allocated = 0;
size_t total_freed = 0;
size_t current_heap_used = 0;
size_t max_heap_used = 0;

static void* my_malloc_hook(size_t size, const void* caller) {
    __malloc_hook = NULL; // 禁用钩子避免递归
    void* ptr = malloc(size);
    if (ptr != NULL) {
        total_allocated += size;
        current_heap_used += size;
        if (current_heap_used > max_heap_used) {
            max_heap_used = current_heap_used;
        }
    }
    __malloc_hook = my_malloc_hook;
    return ptr;
}

static void my_free_hook(void* ptr, const void* caller) {
    __free_hook = NULL;
    if (ptr != NULL) {
        size_t size = malloc_usable_size(ptr); // 获取块实际可用大小
        total_freed += size;
        current_heap_used -= size;
    }
    free(ptr);
    __free_hook = my_free_hook;
}

// 初始化钩子,建议在main开头调用
void init_heap_stats(void) {
    __malloc_hook = my_malloc_hook;
    __free_hook = my_free_hook;
}

三、CI任务适配

  • 栈检查:要么用-fstack-usage生成.su文件,写脚本汇总栈需求并与30KB阈值对比;要么让程序运行时输出max_stack_used,CI捕获输出值做判断。
  • 堆检查:程序运行结束时输出max_heap_used、current_heap_used等指标,CI脚本读取这些值,验证是否在MCU内存限制内。

内容的提问来源于stack exchange,提问作者Galaxo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 05:15:38