zoukankan      html  css  js  c++  java
  • 编译器初始化全局变量,并分配虚拟内存

     版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
    http://www.cnblogs.com/lovers/p/memory.html 

     word版下载

    编译器初始化全局变量,并分配虚拟内存

    目录

    编译器初始化全局变量,并分配虚拟内存... 1

    问题:... 1

    解释:... 1

    执行文件的大小... 1

    什么时候初始化?... 2

    什么时候分配内存?... 3

    为什么程序开始运行时的内存是0.5MB而不是100MB... 3

    总结:... 3

    实验:... 3

    环境... 3

    例程1 没有显示初始化... 4

    例程2 显示初始化... 5

    例程3 没有显示初始化,在main方法中使用全局变量... 7

    例程4 显示初始化,在main方法中使用全局变量... 9

    例程5 没有显示初始化,打印虚拟内存地址... 11

    例程6 显示初始化,打印虚拟内存地址... 12

     

    问题:

    全局变量arr占用100MB空间,arr存放在静态存储区,当程序运行的时候,占用的内存竟然只有几百KB,难道arr没有占用内存?

    解释:

    执行文件的大小

    例程1234可以证明:

    数据段保存在目标文件中。

    BSS不保存在目标文件中(除了记录BSS段在运行时所需要的大小

    该结论引自《C专家编程》6.2节。

        

    执行文件的大小 = BSS + 数据段 + 文本段 + 其他。

     

     例程 

    执行文件大小

    例程1

    7376Byte = 7.2KB

    例程2

    140865010Byte = 134.3MB

    例程3

    7415Byte=7.2KB

    例程4

    140865045Byte = 134.3MB

     

     

     

     

     

     

     

    初始化

    执行文件大小

    没有显示初始化

    7376Byte = 7.2KB

    显示初始化

    140865010Byte = 134.3MB

     

    什么时候初始化?

    1.       手动初始化

    编译时根据赋值进行初始化,存储在数据段

    2.      默认初始化

    编译时初始化,只是记录其大小,存储在BSS

    BSS的值全是0由此可见为什么默认初始化int0char是空了。对于内部类型和枚举默认初始化是0.

    什么时候分配内存?

    编译完,全局变量占用的空间就分配好了。

    编译器给arr[100 * 1024 * 1024]分配的虚拟内存:

    0x804a040

    …………

    0xe44a03f

    结合例程5例程6的结果可知,无论是否显示初始化,编译后全局变量的内存都分配好了,都是虚拟内存

    为什么程序开始运行时的内存是0.5MB而不是100MB

    例程

    是否使用全局变量arr

    进程占用内存

    例程1

    不使用

    0.5MB

    例程2

    0.5MB

    例程3

    main方法中使用全局变量arr

    memset(arr,1,100*1024*1024)

    100.85MB

    例程4

    100.85MB

     

     

     

     

     

    TODO:下面的论述都是跟同学讨论,上网查找的结果,没有经过权威验证

    关于虚拟内存管理请查看:Linux C编程一站式学习----虚拟内存管理

    程序开始运行时,并不会真的把静态存储区全部载入实际内存,只把一部分虚拟内存映射到了实际内存,所以没有访问全局变量arr的时候,进程实际占用内存只有几百KB。当访问全局变量的时候,操作系统才会把这一部分虚拟内存地址映射到实际内存,进程实际占用内存才会到达100MB

    也就是说编译器给全局变量分配的虚拟内存,而我们看到的进程占用的实际内存

    总结:

    根据实验可知,全局变量确实是在编译时,初始化和分配虚拟内存只不过一些实现细节对我们透明了。纸上得来终觉浅,绝知此事要躬行。

    实验:

    环境

    FC18

    GCC

    例程1 没有显示初始化

    源码:

    #include <unistd.h>

    char arr[100 *1024 *1024];//声明了100MB空间,没有显示初始化

    intmain(intargc,char*argv[])

    {

      while(1)

      {

        sleep(1);

      }

      return0;

    }

    汇编:

        .file  "test_uninitialized.cpp"

        .globlarr

        .bss          #未初始化

        .align 32

        .type  arr, @object

        .size  arr, 104857600

    arr:

        .zero  104857600

        .text

        .globlmain

        .type  main, @function

    main:

    ..............

    结果:

        

     

     

    运行时占用的内存:

     

     

     

     

     

     

     

      

    内存总共大小:508740KB /1024 = 497MB 约为 512MB

    进程占用内存:508740KB * 0.001 = 508.74KB /1024 = 0.5MB

    分析:

    test_uni的大小为7376字节。

    bss段是未初始化的全局变量存储区。100 * 1024 * 1024 = 104857600字节。

    例程2 显示初始化

    源码:

    #include <unistd.h>

    char arr[100 *1024 *1024]={'a'};//显示初始化

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

    {

      while(1)

      {

        sleep(1);

      }

      return0;

    }

    汇编:

             .file  "test_initialized.cpp"

        .globlarr

        .data         #需要初始化

        .align 32

        .type  arr, @object

        .size  arr, 104857600

    arr:

        .byte  97

        .zero  104857599

        .text

        .globlmain

        .type  main, @function

    main:

    ..............

    结果:

     

     

    运行时占用的内存:

     

     

     

     

     

     

     

     

    内存总共大小:508740KB /1024 = 497MB 约为 512MB

    进程占用内存:508740KB * 0.001 = 508.74KB /1024 = 0.5MB

    例程3 没有显示初始化,在main方法中使用全局变量

    源码:

    #include <unistd.h>

    #include <string.h>

    char arr[100*1024*1024]; //声明了100MB空间,没有显示初始化

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

    {

      memset(arr,1,100*1024*1024); //arr数组全赋值为1

      while(1)

      {

        sleep(1);

      }

      return0;

    }

    汇编:

             .file  "test_uninitialized2.cpp"

        .globlarr

        .bss

        .align 32

        .type  arr, @object

        .size  arr, 104857600

    arr:

        .zero  104857600

        .text

        .globlmain

        .type  main, @function

    main:

    ..............

    结果:

     

     

     

     

     

     

    与例程1的结果相比,没有多少差别。

    运行时占用的内存:

     

     

     

     

     

     

     

     

    内存总共大小:508740KB /1024 = 497MB 约为 512MB

    进程占用内存:508740KB * 0.203 = 103274.22KB /1024 = 100.85MB

    例程4 显示初始化,在main方法中使用全局变量

    源码:

    #include <unistd.h>

    #include <string.h>

    char arr[100*1024*1024]={'a'};//声明了100MB空间,显示初始化

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

    {

      memset(arr,1,100*1024*1024); //arr数组全赋值为1

      while(1)

      {

        sleep(1);

      }

      return0;

    }

    汇编:

             .file  "test_initialized2.cpp"

        .globlarr

        .data

        .align 32

        .type  arr, @object

        .size  arr, 104857600

    arr:

        .byte  97

        .zero  104857599

        .text

        .globlmain

        .type  main, @function

    main:

    ..............

    结果:


     

     

     

     

     

    与例程2的结果相比,没有多少差别。

    运行时占用的内存:


     

     

     

     

     

     

    内存总共大小:508740KB /1024 = 497MB 约为 512MB

    进程占用内存:508740KB * 0.203 = 103274.22KB /1024 = 100.85MB

    例程5 没有显示初始化,打印虚拟内存地址

    源码:

    #include <unistd.h>

    #include <stdio.h>

    char arr[100*1024*1024];

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

    {

      printf("address of arr[0]                     = %p ",&arr[0]);

      printf("address of arr[100 * 1024 * 1024 - 1] = %p ",&arr[100*1024*1024-1]);

      while(1)

      {

        sleep(1);

      }

      return0;

    }

    结果:


     

     

    arr[100 * 1024 * 1024]的内存分布:

    0x804a040

    …………

    0xe44a03f

    上述空间为100MB

    查看虚拟内存地址:


     

     

     

     

    08048000-08049000

    08049000-0804a000

    0804a000-0804b000

    0804b000-0e44b000// 100MB空间

    最后两段是数据段,其中红色是BSS

    例程6 显示初始化,打印虚拟内存地址

    源码:

    #include <unistd.h>

    #include <stdio.h>

    char arr[100*1024*1024]={'a'};

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

    {

      printf("address of arr[0]                     = %p ",&arr[0]);

      printf("address of arr[100 * 1024 * 1024 - 1] = %p ",&arr[100*1024*1024-1]);

      while(1)

      {

        sleep(1);

      }

      return0;

    }

    结果:


     

     

     

    与例程5的内存地址一样!!神奇地证明了进程中使用的内存地址都是虚拟的。

    arr[100 * 1024 * 1024]的内存分布:

    0x804a040

    …………

    0xe44a03f

    上述空间为100MB

    查看虚拟内存地址:


     

     

     

     

     

    08048000-08049000

    08049000-0804a000

    0804a000-0e44b000// 约为100 MB空间

    最后一段是数据段,不同的是例程6没有BSS

     

     

  • 相关阅读:
    Kafka(Go)系列(一)通过dockercompose 安装 Kafka
    grpc通过自签CA证书、server、client双向认证【支持go1.15】
    Go 基准测试和性能测试学习使用
    Debian关闭防火墙
    服务依赖开闭简单算法
    Hbase 和 Hive 的区别,各自使用场景。
    VMware虚拟机 Ubuntu1404
    安装protoc
    Redis大 key 自动过期的问题
    MySQL设置数据库为只读
  • 原文地址:https://www.cnblogs.com/lovers/p/memory.html
Copyright © 2011-2022 走看看