zoukankan      html  css  js  c++  java
  • 笔记:程序内存管理 .bss .data .rodata .text stack heap

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

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

    #include<stdio.h>
    
    int bss_array[1024*1024];
    int main(int argc, char *argv[])
    {  
        return 0;
    }
    

     编译并查看:

    $ 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
    
    $ 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:

    #include<stdio.h>
    
    int data_array[1024*1024]={1};
    int main(int argc, char *argv[])
    { 
        return 0;
    }
    

     编译查看

    [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 

    #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
    ");
            return -1;
        }
        free(p);
        printf("p = %4x
    ",p);
        p = NULL;
        printf("p = %4x
    ",p);
        return 0;
    }
    

     程序运行结果:

    [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()函数

    void *calloc(size_t nmemb, size_t size);
    

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

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

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

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

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

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

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

    2)realloc()函数

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

    定义:

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

     用法示例:

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

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

    摘录书籍

    《ARM嵌入式Linux系统开发详解》 弓雷 等编著

    《高质量嵌入式Linux C编程》 梁庚 等编著

  • 相关阅读:
    Single Number II
    Pascal's Triangle
    Remove Duplicates from Sorted Array
    Populating Next Right Pointers in Each Node
    Minimum Depth of Binary Tree
    Unique Paths
    Sort Colors
    Swap Nodes in Pairs
    Merge Two Sorted Lists
    Climbing Stairs
  • 原文地址:https://www.cnblogs.com/hythink/p/5422602.html
Copyright © 2011-2022 走看看