程序内存管理 .bss .data .rodata .text stack heap

1.未初始化的全局变量(.bss段)

bss段用来存放 没有被初始化 和 已经被初始化为0 的全局变量。如下例代码:

1

2

3

4

5

6

7

#include<stdio.h>

 

int bss_array[1024*1024];

int main(int argc, char *argv[])

    return 0;

}

 编译并查看:

1

2

3

4

5

6

$ gcc -g mainbss.c -o mainbss

$ ls -l mainbss

-rwxrwxr-x. 1 hy hy 8330 Apr 22 19:33 mainbss

$ objdump -h mainbss |grep bss

mainbss:     file format elf32-i386

 24 .bss          00400020  0804a020  0804a020  00001018  2**5

1

2

3

$ size mainbss

   text    data     bss     dec     hex filename

   1055     272 4194336 4195663  40054f mainbss

     全局变量bss_array的大小为4MB = 1024*1024*sizeof(int) Byte = 4194304 Byte。 通过size 查看可知数据被存在了 bss 段

  而 可执行文件mainbss 有8KB左右,命令 ls -l mainbss 查看得知。可知,bss类型的全局变量只占用 运行时的内存空间,而不占用可执行文件自身的文件空间

 

2017-11-24

    今天再读此书时,联想到 OR1200 编译过程中的 RAM 和 链接脚本,产生一个问题。在 OR 仿真验证中,我的RAM只有8KB的空间,若我有一个定义上诉数组,可执行文件本身不大,但是运行时需要占用4M的空间。那程序岂不是会崩溃? 带着这个问题。在OR的验证程序中做了测试。

个人结论: 若在运行时这个空间不足的问题,编译器会帮忙检查的。这些是数据,若是在运行时的 堆和栈 不足,这点编译器没法检查。

复制代码

#include"uart.h"
volatile unsigned long timestamp = 0;

#define   DRAM_MEM_SIZE       (0x200)
#define   DRAM_ADDR_START     (0x1FFF-DRAM_MEM_SIZE+1)
#define   DRAM_ADDR_END       (0x1FFF)

#define Struct_Section  __attribute__((unused, section(".stdata_mem_type"), \
                aligned(4)))

typedef unsigned int u32;
typedef signed int   s32;

 char txbuf[]={0x01,0x03,0x07,0x0f,0x10,0x30,0x70};
 char testbss;
 char testdata=10;
 typedef  struct {
        char ch[4];
        unsigned int addrinit;
        unsigned int len;
 }STDATA_MEM_TYPE;
STDATA_MEM_TYPE arry_dynamic Struct_Section;
int t_array[1024*1024]={};

int main(void)
{
//省略
}

复制代码

编译报错如下, .bss 段不够用:

复制代码

openrisc@openrisc-VirtualBox:~/mc-or-lngit/or_bootsim_shpy/hyor_ramboot$ make
or32-elf-gcc -c reset.S -o reset.o
or32-elf-gcc -c main.c -o main.o
or32-elf-gcc -c uart.c -o uart.o 
or32-elf-ld reset.o main.o uart.o -T ram.ld -o hyor_ramboot.or32 
or32-elf-ld: hyor_ramboot.or32 section `.bss' will not fit in region `ram'
or32-elf-ld: region `ram' overflowed by 4192276 bytes
make: *** [hyor_ramboot.or32] Error 1

复制代码

 

2. 已被初始化为非零的全局变量(.data段)

  data段用来存放已经被初始化为非零的全局变量。如下代码,只将矩阵的第一个元素初试化为1:

1

2

3

4

5

6

7

#include<stdio.h>

 

int data_array[1024*1024]={1};

int main(int argc, char *argv[])

{

    return 0;

}

 编译查看

1

2

3

4

5

6

7

8

[hy@localhost memcfg]$ gcc -g maindata.c -o maindata

[hy@localhost memcfg]$ ls -l maindata

-rwxrwxr-x. 1 hy hy 4202682 Apr 22 19:48 maindata

[hy@localhost memcfg]$ objdump -h maindata |grep \\.data

 23 .data         00400020  0804a020  0804a020  00001020  2**5

[hy@localhost memcfg]$ size maindata

   text    data     bss     dec     hex filename

   1055 4194604       4 4195663  40054f maindata

 而 可执行文件maindata 有4MB左右。通过size 查看可知数据被存在了 data 段

可知,data类型的全局变量既占用运行时的内存空间,也占用可执行文件自身的文件空间

3.常量数据(.rodata段)

 1)rodata用来存放常量数据。 ro: read only

 2)字符串会被编译器自动放在rodata中,加 const 关键字的常量数据会被放在 rodata 中

 3)在有的嵌入式系统中, rodata放在 ROM(或 NOR Flash)里,运行时直接读取,不须加载到RAM内存中。

     所以,在嵌入式开发中,常将已知的常量系数,表格数据等造表加以 const 关键字。存在ROM中,避免占用RAM空间。

4.代码(.text段)

  text段存放代码(如:函数)和部分整数常量(应该指的是一些立即数),这个段是可执行的。

5.栈(stack)

  1)stack 存放函数的局部变量和函数参数

  2)被调用函数的参数和返回值 被存储到当前程序的栈区,之后被调用函数再为自身的自动变量和临时变量在栈区上分配空间

  3)函数返回时,栈区的数据会被释放掉,先入后出(FILO)的顺序。

6.堆(heap)

  heap用来动态分配内存,由程序自身决定开辟和释放。

 6.1 malloc/free 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include<stdio.h>

#include<stdlib.h>

 

int main(int argc, char *argv[])

{

    int *p = (int *)malloc(10*1);

    // p= (int *)malloc(10*1);

    if(p==NULL) {

        printf("malloc p err\n");

        return -1;

    }

    free(p);

    printf("p = %4x\n",p);

    p = NULL;

    printf("p = %4x\n",p);

    return 0;

}

 程序运行结果:

1

2

3

4

[hy@localhost memcfg]$ gcc maindata.c

[hy@localhost memcfg]$ ./a.out

p = 9cf4008

p =    0

 1)开辟了空间,就要适时的释放。释放时,指针应指向开辟时的内存空间,所以在使用指针时,要注意不要修改了其地址,或者将开辟时的起始地址保存起来。

 2)对指针free后,其地址不一定就为NULL。如代码中的 p,在 free(p)后,printf("p=%4x",p)后并非为0。所以建议在free(p)后,立即加一句p=NULL。

 3)检查p的地址 if(p!=NULL){ ... }

6.2 calloc/realloc

 1)calloc()函数

1

void *calloc(size_t nmemb, size_t size);

   参数nmemb 表示要分配元素的个数,size表示每个元素的大小,分频的内存空间大小是 nmemb*size; 返回值是 void* 类型的指针,指向分配好的内存首地址。

 用法一:分配1024*sizeof(int)字节大小的内存,并清空为0

1

int *p = (int *)calloc(1024,sizeof(int));

  用法二:与 alloc等价的 malloc 用法

1

2

int *p = (int *)malloc(1024*sizeof(int));

memset(p,0,1024*sizeof(int));

 差异:用法一calloc,会根据分配的的类型来初始化为0,如:分配int型,则初始化为(int)0; 若为指针类型,则初始化为空指针;若为浮点,则初始化为浮点型。

    用法二memset,不能保证初试化为空指针值和浮点型。(与NULL常量和浮点型的定义有关)

2)realloc()函数

  realloc()用来重新分配正在使用的一块内存大小。

定义:

1

void *realloc(void *ptr, size_t size);

 用法示例:

1

2

3

int *p = (int *)malloc(1024);    //

p = (int *)realloc(512);        // 重新分配为 512字节大小内存,缩小数据丢失

p = (int *)realloc(2048);      // 重新分配为2048字节大小内存   

 注意:经过realloc()调整后的内存空间起始地址有可能与原来的不同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值