• 读《高质量C/C++》 存储


    今天来进一步了解一下C/C++的存储相关的东西。
    首先,编程有哪几种数据区域?
    其次,C/C++怎样来定义不同区域的数据?
    再次,这几种区域的数据的生存周期是怎样的?
    最后,不同区域的数据的访问规则是什么?
    首先,相信大家都应该知道,静态区域、堆栈区域和堆区域数据,我个人的理解都是物理内存地址,适当的做了区域划分,而这三类地址为编程常用内存存储,而另外还有一类特殊的高效存储应该就是寄存器。
    其次,我们了解下这三种存储的定义方式
    1、静态区域数据,通过static或者extern(默认不带,或者带)定义的内容,例如:
    // static 定义的静态区数据测试
    static int index    = 1000 ;  
    static int iniIndex = 2000 ;  
    void getYear(void)
    {
    static int year = 2012;
    printf( "STATIC MEM:year@0x%p \t\t= %d\r\n",&year,year );
    }
    int main(int argc, char** argv)
    {
    static int age = 27 ;
    int day = 21;
    int month = 8;
    printf( "STACK MEM:day@0x%p \t\t= %d\r\n",&day,day );
    printf( "STACK MEM:month@0x%p \t\t= %d\r\n",&month,month );
    printf( "STATIC MEM:index@0x%p \t\t= %d\r\n",&index,index );
    printf( "STATIC MEM:iniIndex@0x%p \t\t= %d\r\n",&iniIndex,iniIndex );
    printf( "STATIC MEM:age@0x%p \t\t= %d\r\n",&age,age );
    getYear();
    return 0;
    }
    // 输出结果
    STACK MEM:day@0x0012FF60                = 21    // 堆栈数据信息,和static定义的区域内存地址不一样
    STACK MEM:month@0x0012FF54              = 8  // 堆栈数据信息,和static定义的区域内存地址不一样
    STATIC MEM:index@0x00419034             = 1000  // 虽然在不同代码段中用static定义,但是内存是连续的
    STATIC MEM:iniIndex@0x00419038          = 2000 // 虽然在不同代码段中用static定义,但是内存是连续的
    STATIC MEM:age@0x00419040               = 27 // 虽然在不同代码段中用static定义,但是内存是连续的
    STATIC MEM:year@0x0041903C              = 2012 // 虽然在不同代码段中用static定义,但是内存是连续的
    请按任意键继续. . .
    // extern 定义的静态区域数据测试
    extern int exINT    = 10000; // 在 static int iniIndex = 2000 ;  添加
    int defaultExInt    = 100000;
    printf( "STATIC MEM:iniIndex@0x%p \t\t= %d\r\n",&exINT,exINT ); // 在 printf( "STATIC MEM:iniIndex@0x%p \t\t= %d\r\n",&iniIndex,iniIndex );后添加。
    printf( "STATIC MEM:iniIndex@0x%p \t\t= %d\r\n",&defaultExInt,defaultExInt );
    //输出结果
    STACK MEM:day@0x0012FF60                = 21
    STACK MEM:month@0x0012FF54              = 8
    STATIC MEM:index@0x00419034             = 1000
    STATIC MEM:iniIndex@0x00419038          = 2000
    STATIC MEM:exINT@0x0041903C             = 10000
    STATIC MEM:defaultExInt@0x00419040      = 100000
    STATIC MEM:age@0x00419048               = 27
    STATIC MEM:year@0x00419044              = 2012
    请按任意键继续. . .
    //C/C++中,默认全局的定义默认类型是extern,所以我们会得出 exINT和defaultExInt都会在静态区域中。
    // 总结,凡通过static或者extern(包括不加extern的)都会在静态区域中定义数据。
    2、堆栈数据,当然就是我们定义的程序块中的临时数据,作用域最小。
    3、堆上数据,这部分是由我们自动申请、释放的内存。例如:
    // heap memory ;在上面程序段添加
    int *mallocData = new int[2];
    memset( mallocData,0,2*sizeof(int) );
    printf( "HEAP MEM:mallocData1@0x%p \t\t= %d\r\n",&mallocData[0],mallocData[0] );
    printf( "HEAP MEM:mallocData2@0x%p \t\t= %d\r\n",&mallocData[1],mallocData[1] );
    delete[] mallocData;
    mallocData = NULL;
    // 输出结果
    // 堆栈内存分布
    STACK MEM:day@0x0012FF60                = 21
    STACK MEM:month@0x0012FF54              = 8
    // 静态区域内存分布
    STATIC MEM:index@0x00419034             = 1000
    STATIC MEM:iniIndex@0x00419038          = 2000
    STATIC MEM:exINT@0x0041903C             = 10000
    STATIC MEM:defaultExInt@0x00419040      = 100000
    STATIC MEM:age@0x00419048               = 27
    STATIC MEM:year@0x00419044              = 2012
    // 自定义内存分布
    HEAP MEM:mallocData1@0x003956F8         = 0
    HEAP MEM:mallocData2@0x003956FC         = 0
    请按任意键继续. . .
    总结,物理内存是单一的,对程序而言却可以定义不同区域的内存。
    另外,还有一类特殊存储,寄存器存储。register定义的变量,该变量会被在CPU寄存器容量允许的情况下直接被加载。CPU访问内存单元时,先见内存单元的地址加载到地址总线(AB)上,同时将内存电路的“读写控制”设置为有效,然后内存单元中的数据就通过数据总线(DB)“流”向了接受的寄存器中,或方向流向内存单元中。这样理解就可以知道register的好处。但CPU寄存器地址毕竟是有限的,所以在高性能优化时可以适量采用。
    再次,我们在来了解这三种区域的生存周期和作用域。
    对于生命周期的理解,分为永久性、临时性和自由性。对于我们静态区域的数据,我们一旦定义了就永久的存在静态内存区域中;而堆栈区域的数据,具有临时性,在程序块的作用范围内,然而对于自由区域数据就完全靠我们自己来申请和释放,如果不用又不释放那就产生内存垃圾,如果这段程序段又在整个生命期不断被调用,那么内存就不断被消耗,就是所谓的内存泄漏。
    对于数据区的周期有所了解后,其实对作用域也显而易见,整个生命期都存在的内存肯定可以被当前单一编译单元操作,临时性的内存不具备可控性,只能在其生命期内可以操控,所以就看你怎么确定他的生命期,只要在生命期内都可以操控。
    最后,在分享一下在不同编译单元中的作用域问题。
    这里需要提到 extern关键字,当一个变量的声明中指定了extern时候,这个变量就可以被被引用的编译单元访问。例如:
    a.h
    extern int g_NUMBER;
    a.cpp
    int g_NUMBER = 10000;
    m.cpp
    #include "a.h"
    int main( int agrc,char** argv )
    {
    printf( "g_NUMBER@0x%p \t= %d\r\n",&g_NUMBER,g_NUMBER );
    return 0;
    }
    谢谢。
  • 相关阅读:
    Sqlserver 批量数据更改
    mysql not in、left join、IS NULL、NOT EXISTS 效率问题记录
    SQLServer 与 MySQL
    MySQL 行号(类似SQLServer的row_number())
    c# 字符串排序 (面试题)
    c# 多线程里面创建byte数组发生内存溢出异常求解
    c# 遇到的问题,求解?
    solr-4.10.3.tgz.tgz下载
    VMware虚拟机克隆或复制linux后无法上网的解决方案
    通配符的匹配很全面, 但无法找到元素 'dubbo:application' 的声明。
  • 原文地址:https://www.cnblogs.com/CHENYO/p/2649993.html
Copyright © 2020-2023  润新知