关于Linux C 程序的内存分配

    根据《unix高级环境编程》书中,一个程序分为如下5段:

代码段(text),data(已初始化)段,bss段(未初始化),栈,堆。

1. 一般情况下,一个可执行的二进制程序拥有3个部分:

可执行的二进制程序 == 代码段 + data 段 + bss 段

2. 程序被加载到内存中,还需要堆区和栈区(栈由系统分配和管理,堆由程序员手动分配和释放)

正在运行的二进制程序 == 代码段 + data段 + bss段 + 堆区 + 栈区  

3. 动态分配和静态分配,二者最大的区别在于,静态分配是在编译时(complie-time)就已经决定了分配多少内存text+data+bss+stack,而动态分配是直到运行时(Run-time)才分配内存。通过malloc、realloc和calloc分配的内存,必须手动free(). 否则引起内存泄露。

data段和bss段的区别是,bss并不占用可执行文件的大小。

以下具体说明每一段

text段:可执行代码,只读的,字符串常量、const全局;

data段:静态初始化的数据、有初值(不为0)static变量;

bss段:未初始化的全局变量,和全局静态变量;

栈:保存函数的局部变量,函数的参数、返回值或返回的地址;

堆:动态内存分配,程序员手动分配和释放,不释放会引起内存泄露

附上测试程序:

#include<stdio.h>
#include<malloc.h>
#include<string.h>
const int g_a = 10;//text
int g_b = 20;//data
static int g_c = 30;//data
static int g_d;//bss
int g_e;//bss
char *p1;//bss

int main(void)
{
	int l_a ,la; //stack
	const int  l_b;//stack
	static int l_c = 0;//bss
	static int l_d;//l_d==0, bss
	static int l_e = 5;//data
	printf("l_d = %d\n", l_d);
	char *p = "123456789"; //p in stack; "123456789" in text
	p1 = (char *) malloc(10);//p1  in  heap
	strcpy(p1, "24680"); 
	
	printf("high address\n");
	printf("------------栈------------\n");
	printf("l_a address = %p\n", &l_a);
	printf("la address = %p\n", &la);
	printf("l_b address = %p\n", &l_b);
	printf("------------堆------------\n");
	printf("p1 value = %p\n", p1);
	printf("------------代码段------------\n");
	printf("g_a address = %p\n", &g_a);
	printf("------------bss------------\n");
	printf("g_d address = %p\n", &g_d);
	printf("g_e address = %p\n", &g_e);
	printf("p1 address = %p\n", &p1);
	printf("l_c address = %p\n", &l_c);
	printf("l_d address = %p\n", &l_d);
	printf("------------data------------\n");
	printf("g_b address = %p\n", &g_b);
	printf("g_c address = %p\n", &g_c);
	printf("l_e address = %p\n", &l_e);
	printf("low address\n");

	return 0;
}
执行结果:

root@liujie-desktop:/soft# ./t
l_d = 0
high address
------------栈------------
l_a address = 0xbfe5db8c
la address = 0xbfe5db88
l_b address = 0xbfe5db84
------------堆------------
p1 value = 0x9295008
------------代码段------------
g_a address = 0x8048710
------------bss------------
g_d address = 0x804a034
g_e address = 0x804a044
p1 address = 0x804a040
l_c address = 0x804a03c
l_d address = 0x804a038
------------data------------
g_b address = 0x804a020
g_c address = 0x804a024
l_e address = 0x804a028
low address
从结果来分析,

1. const 全局 g_a 存放在text;

2. const 局部 l_b 存放在栈中;

3. l_c 初始化为0 其实和l_d是一样的,l_d也为0,存放在bss,&p1也在bss;
备注:编译时需要加 -g 选项,这样才可以看elf信息;

readelf  -a  t  可以看到其中的.data .text. .bss。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux下,可以使用以下方法来预先分配一块内存: 1. 使用kmalloc函数,该函数可以分配指定大小的内存块,并返回该内存块的指针。该函数适用于需要在运行时动态分配内存的场景。例如: ```c #include <linux/slab.h> ... void *ptr = kmalloc(size, GFP_KERNEL); if (!ptr) { // 分配内存失败,进行错误处理 } ``` 2. 使用vmalloc函数,该函数可以分配大块的虚拟内存,并返回该内存块的指针。该函数适用于需要分配大块内存的场景,例如网络协议栈和文件系统缓存等。例如: ```c #include <linux/vmalloc.h> ... void *ptr = vmalloc(size); if (!ptr) { // 分配内存失败,进行错误处理 } ``` 3. 使用bootmem机制,该机制可以在内核启动时预先分配内存。在内核启动时,可以使用reserve_bootmem函数来分配保留区域,并使用该区域来存储内核数据结构和驱动程序等。例如: ```c #include <linux/bootmem.h> ... struct my_data *data; // 在内核启动时分配保留区域 data = reserve_bootmem(size); // 使用保留区域来存储数据 data->a = 1; data->b = 2; ... ``` 4. 使用SLUB分配器,该分配器是Linux内核中的一种内存分配器,可以动态分配、释放内存。SLUB分配器提供了高效的内存分配和管理方式,适用于大多数场景。例如: ```c #include <linux/slab.h> ... void *ptr = kmalloc(size, GFP_KERNEL); if (!ptr) { // 分配内存失败,进行错误处理 } ``` 以上是Linux下常用的预先分配内存的方法。根据具体的应用场景和需求,可以选择合适的方法来分配和管理内存。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值