如何分析C语言程序的内存占用

您所在的位置:网站首页 miui11占用多少运存 如何分析C语言程序的内存占用

如何分析C语言程序的内存占用

2024-07-02 14:47| 来源: 网络整理| 查看: 265

问题

如何分析C语言程序的内存占用,特别是全局/静态变量的内存占用?

结论先行 除少数典型场景,不应该存在比较多,或大的全局/静态变量使用情况应根据内存生命周期的情况,尽量使用栈上临时空间,再次之应使用堆空间(池)

注:

全局/静态变量应作为系统自举的根信息存在,在所有组件间共享。其它变量往往比较局部,工作层次不尽相同,可利用上下文结构体进行层次的划分,而不应该都在全局变量空间,作为底部基座存在。 如果以树形结构来来看待变量的工作层次,全局/静态变量就在整个系统的根上,而其它组件的分支上下文结构体变量,则是它们各自子树的根! 设计之美

不使用全局变量,虽然最初用起来别扭,但是,确实一种很好,很有美感的设计,体现了高内聚、低耦合,封装的美感!

全部使用全局变量,可视为一种无设计的懒惰,实践者并没有想好整个系统的架构模型,是怎样一棵树,或一片森林!

理论 .data段展现了全局/静态变量非零初值的分配情况.bss段展现了全局/静态变量初值为零分配情况两个段均符合Linux管理内存的金贵原则,表现为内存实际访问时,才转换为物理内存,没有被访问前,仅表现为虚存的内存申请量 内存的金贵

在linux中,即使对于.data or .bss的全局/静态变量,也采用延迟分配物理内存的策略,与堆空间一样。

这个可以从top -p $pid进行逐步的分析、查看VIRT、RES统计项的变化,不赘述。

注:文末有验证例子代码

所以,从这个角度来看,将内存放在全局占用,还是栈空间占用,抑或在堆空间,对于物理内存的占用来说,区别并不是非常大,但,还是有致命的区别!

内存使用,考察的首要因素,就是它的生命周期,用更合适的内存空间生命周期模型!

临时空间占用,将会因生命周期的结束,而释放掉物理内存占用!

但对比来看,已访问过的全局/静态变量,则不会!

所以,区别二者的不同,很重要 😃

序列图图解

在这里插入图片描述

临时空间编程技术手段

通用手段

将地址空间,例如,上下文信息,作为函数入参,避免进行全局名称访问,以利于更好的模块封装性,向函数编程分形靠齐

临时空间内存大小的判断标准,为系统栈空间门限ulimit -s,例如,CentOS7为8M,已相当不小!

对于普通大小的临时内存,建议使用:

栈上临时内存C99以来支持的函数内部使用可变长数组

注:

栈空间内存优势在于内存生命周期的自动管理,能够将代码写的更简洁 能够将代码写的更短,又不影响可读性的技术,都是好手段

对于较大的内存,建议使用:

堆空间动态申请/动态释放,以及可能巨量内存需要结合巨页的使用方式

页表过多,会对于内存访问存在比较大的影响;对于巨量内存使用,应考虑使用巨页技术

缘由

近期由于一个硬件环境受限制的需求,需要对已有的程序进行裁剪内存占用。

对于进程启动后,新内存申请,一般可以通过valgrind等工具予以很好的分析。

但是,对于全局/静态变量的占用情况如何分析呢?

对于规模比较小的应用,可以通过个人编程经验进行精确地定位当应用复杂度到达一定程度,必须在经验之外,结合使用工具进行兜底 分析全局变量内存占用情况工具 size

从概况上进行分析,分析某个可执行程序文件或库文件的.data or .bss段占用情况

size /path/to/yourexcutablefile # outpuit text data bss dec hex filename 3699 2097896 4194312 6295907 601163 a.out .data段会占用文件大小,而.bss段不会占用文件大小,仅会在程序加载的时间进行分配,和初始化 可以利用大块全局变量设定非零的初值进行验证 建议全局变量都以零值初值起步,采用main运行后设定非零初值的策略,有利于加速程序load gdb命令具体分析 gdb att $(pidof a.out) # 利用info variables命令进行查看 (gdb) set logging file gdbout.txt (gdb) set logging overwrite on (gdb) set logging on (gdb) info vairables

注:输出全局变量,仅需要关注自身代码相关的全局变量声明

valgrind 分析程序启动后的运行期间内存申请情况 补充 C语言例子 {#example} #include #include #include #include #include // data段 unsigned char g_abBufferAtDataSegment[2 * 1024 * 1024] = { [0 ... (sizeof(g_abBufferAtDataSegment) - 1)] = 0xff }; // bss段 unsigned char g_abBufferAtBssSegment[4 * 1024 * 1024]; int main(void) { char szInputBuffer[256]; printf("global variable at dss segment: %zu, at bss segment: %zu, but only in VIRT space\nEnter any key to continue:", sizeof(g_abBufferAtDataSegment), sizeof(g_abBufferAtBssSegment)); fgets(szInputBuffer, sizeof(szInputBuffer), stdin); printf("Will access the global memory, to see the RES stat change\nEnter any key to continue:"); for(unsigned int i= 0; i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3