如何分析C语言程序的内存占用
创作时间:
作者:
@小白创作中心
如何分析C语言程序的内存占用
引用
CSDN
1.
https://blog.csdn.net/jkler_doyourself/article/details/139011980
在C语言程序开发中,内存占用是一个重要的性能指标。本文将详细介绍如何分析C语言程序的内存占用,特别是全局/静态变量的内存占用情况。通过理论讲解、实践指导和具体工具使用说明,帮助开发者更好地理解和优化程序的内存使用。
问题
如何分析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语言例子
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/resource.h>
// 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< sizeof(g_abBufferAtDataSegment); ++i)
{
g_abBufferAtDataSegment[i] = g_abBufferAtDataSegment[i];
}
for(unsigned int i= 0; i< sizeof(g_abBufferAtBssSegment); ++i)
{
g_abBufferAtBssSegment[i] = g_abBufferAtBssSegment[i];
}
fgets(szInputBuffer, sizeof(szInputBuffer), stdin);
struct rlimit rl = {};
if (getrlimit(RLIMIT_STACK, &rl) == 0) {
printf("Current stack size soft limit: %ld bytes, %ld MB\n", (long)rl.rlim_cur, (long)rl.rlim_cur/(1024*1024));
printf("Current stack size hard limit: %ld bytes, %ld MB\n", (long)rl.rlim_max, (long)rl.rlim_max/(1024*1024));
}
printf("Enter the size factor of statck dynamic array(Unit: MB); q char will exit!\n");
while (fgets(szInputBuffer, sizeof(szInputBuffer), stdin)) {
if (szInputBuffer[0] == 'q')
break;
// 使用M级别以利于观察
unsigned int size = atoi(szInputBuffer);
unsigned char tmpBuffer[size * (1024 * 1024)];
memset(tmpBuffer, 0, sizeof(tmpBuffer));
printf("Memset the temp buffer, to see the memory uasge\n");
}
printf("Exit from program!\n");
return 0;
}
编译脚本
.PHONY: globalMemoryUsage
CCFLAGS := -g3 -O0 -W -Wall -std=gnu11 -pipe -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -Wno-unused-variable -Wno-unused-but-set-variable
globalMemoryUsage: main.c
@echo "test globalMemoryUsage program ..."
gcc $(CCFLAGS) $^ $(LDFLAGS)
注: 需要采用高版本编译标准,以支持将.data段全局变量设定为非零固定值
热门推荐
武汉去腾冲更佳交通工具选择:路线与旅游线路综合指南
办理户口需要什么材料
文科生怎么学计算机
为什么高铁发车前10分钟才检票?这些乘车注意事项请收好
拉萨市消防救援支队开展“盲盒”派送活动
吸附剂对吸附质的影响:作用机制与实践应用
上海市政府已批复!重磅规划来了,涉及闵行
怎么才能创作出符合SEO优化的高质量文章?有哪些技巧和步骤?
油菜花拍照指南:10个姿势,拍出油画质感,大方优雅好看
山东长岛:从保护生态到迈向零碳
猫咪年纪越大越喜欢温热的食物吗?
如何有效的冥想?
健康成年猫咪也需要定期进行健康检查吗?2024年最新研究表示:要!
打印机出现黑色横条怎么办?5个实用解决方案帮你轻松应对
库存车购车指南:辨别与购买技巧全解析
伤官格走偏印运:命理解析与影响
酸中毒症状及危害
代谢性酸中毒分类:原发性与继发性
胆结石疼怎么缓解
肺部CT检查报告单怎么看
人性是什么,如何才能拿捏人性?
中国华能加快推动能源清洁低碳转型
屋里面有蚂蚁怎么处理?杀蚂蚁最有效的杀虫剂指南大公开
高速救援收费那些事儿:明明白白看懂收费标准
菠菜为什么不能和牛肉一起吃
煮速冻饺时,直接下锅是错误的,少这几步,难怪馅料没熟,皮先破
风车茉莉怎么浇水(茉莉的浇水频率和注意事项)
AI技术在健康管理平台中的智能健康数据挖掘技术深度解析
拔牙后麻醉会持续多久?消失的时间和影响因素解析
肺炎患者可以摄取水果吗