zoukankan      html  css  js  c++  java
  • C++内存管理——内存分配

    1、C++编译的程序占用的内存分类

    (1)栈区(stack):程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。程序结束时由编译器自动释放

    (2)堆区(heap) :在内存开辟另一块存储区域。一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。

    (3)全局静态区(static):编译器编译时即分配内存。全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。

    (4)文字常量区 :常量字符串就是放在这里的。 程序结束后由系统释放。

    (5)程序代码区:存放函数体(类成员函数和全局函数)的二进制代码。

    2、内存分配方式有三种

    (1)从静态存储区域分配:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。

    (2)在栈上创建:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存 分配运算 内置于 处理器的指令集中,效率很高,但是分配的内存容量有限。

    (3)从堆上分配:亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

    3、C++变量内存分布

    通过程序加以说明

    (1)变量分布

    View Code 1
    #include <stdio.h>   
    #include <malloc.h>
    int g_i = 100;
    int g_j;
    int main()
    {
    const int MAXN = 100;
    int *p = (int*)malloc(MAXN * sizeof(int));
    static int s_i = 5;
    static int s_j;
    int i = 5;
    int j;
    char k='a';
    char *pstr1 = "MoreWindows123456789";
    char *pstr2 = "MoreWindows123456789";
    char *pstr3 = "Hello";
    printf("堆中数据地址:0x%08x\n", p);
    putchar('\n');
    printf("栈中数据地址(有初值):0x%08x = %d\n", &i, i);
    printf("栈中数据地址(无初值):0x%08x = %d\n", &j, j);
    printf("栈中数据地址(有初值):0x%08x = %c\n", &k, k);
    putchar('\n');
    printf("静态数据地址(有初值):0x%08x = %d\n", &s_i, s_i);
    printf("静态数据地址(无初值):0x%08x = %d\n", &s_j, s_j);
    putchar('\n');
    printf("全局数据地址(有初值):0x%08x = %d\n", &g_i, g_i);
    printf("全局数据地址(无初值):0x%08x = %d\n", &g_j, g_j);
    putchar('\n');
    printf("字符串常量数据地址:0x%08x 指向 0x%08x 内容为-%s\n", &pstr1, pstr1, pstr1);
    printf("字符串常量数据地址:0x%08x 指向 0x%08x 内容为-%s\n", &pstr2, pstr2, pstr2);
    printf("字符串常量数据地址:0x%08x 指向 0x%08x 内容为-%s\n", &pstr3, pstr3, pstr3);
    printf("const常量数据地址 :0x%08x=%d\n",&MAXN,MAXN);
    free(p);
    return 0;
    }

    运行结果:

    运行结果
    堆中数据地址:0x003820d0
    栈中数据地址(有初值):0x0012ff74 = 5
    栈中数据地址(无初值):0x0012ff70 = -858993460
    栈中数据地址(有初值):0x0012ff6c = a
    静态数据地址(有初值):0x00424a34 = 5
    静态数据地址(无初值):0x00427c48 = 0
    全局数据地址(有初值):0x00424a30 = 100
    全局数据地址(无初值):0x00427c44 = 0
    字符串常量数据地址:0x0012ff68 指向 0x004221d8 内容为-MoreWindows123456789
    字符串常量数据地址:0x0012ff64 指向 0x004221d8 内容为-MoreWindows123456789
    字符串常量数据地址:0x0012ff60 指向 0x004221d0 内容为-Helloconst常量数据地址 :0x0012ff7c=100
    Press any key to continue

    分析结果(debug):

    a.变量在内存地址的分布为:栈-堆-代码区-全局静态-文字常量区

    b.同一区域的各变量按声明的顺序在内存的中依次由低到高分配空间,但栈中是由高到低的

    c.全局变量和静态变量如果不赋值,默认为0。 栈中的变量如果不赋值,则是一个随机的数据。

    d.编译器会认为全局变量和静态变量是等同的,已初始化的全局变量和静态变量分配在一起,未初始化的全局变量和静态变量分配在另一起。

    (2)函数分布

    View Code 2
    #include <stdio.h>   
    void fun(int i)
    {
    int j = i;
    static int s_i = 100;
    static int s_j;
    printf("子函数的参数: 0x%p = %d\n", &i, i);
    printf("子函数 栈中数据地址: 0x%p = %d\n", &j, j);
    printf("子函数 静态数据地址(有初值): 0x%p = %d\n", &s_i, s_i);
    printf("子函数 静态数据地址(无初值): 0x%p = %d\n", &s_j, s_j);
    }
    int main()
    {
    int i = 5;
    static int s_i = 100;
    static int s_j;
    printf("主函数 栈中数据地址: 0x%p = %d\n", &i, i);
    printf("主函数 静态数据地址(有初值): 0x%p = %d\n", &s_i, s_i);
    printf("子函数 静态数据地址(无初值): 0x%p = %d\n", &s_j, s_j);
    putchar('\n');
    fun(i);
    return 0;
    }

    运行结果:

    运行结果
    主函数 栈中数据地址: 0x0012FF7C = 5
    主函数 静态数据地址(有初值): 0x00424A34 = 100
    子函数 静态数据地址(无初值): 0x00427C48 = 0
    子函数的参数: 0x0012FF28 = 5
    子函数 栈中数据地址: 0x0012FF1C = 5
    子函数 静态数据地址(有初值): 0x00424A30 = 100
    子函数 静态数据地址(无初值): 0x00427C44 = 0
    Press any key to continue

    结果分析:

    主函数中栈的地址都要高于子函数中参数及栈地址,证明了栈的伸展方向是由高地址向低地址扩展的。主函数和子函数中静态数据的地址也是相邻的,说明程序会将已初始化的全局变量和静态变量分配在一起,未初始化的全局变量和静态变量分配在另一起。





  • 相关阅读:
    布局类组件介绍
    容器类组件介绍
    应用升级介绍
    Http组件的介绍
    Webview组件和HTML的介绍
    数据绑定介绍
    业界最具影响力MySQL精品文章荟萃(300篇)
    业界最有价值的 ASP.NET 博文汇总
    一个引号导致1个小时网站打不开
    这个世界从来没有任何一件工作叫“钱多、事少、离家近”
  • 原文地址:https://www.cnblogs.com/fly1988happy/p/2253207.html
Copyright © 2011-2022 走看看