• 学习堆与栈内存分配方式


    本来想用对和栈的空间分配方法去实现类似于sizeof的功能,结果各种问题,相同的代码VS出来24,VC出来8,更有malloc函数分配1字节内存时,相邻空间间隔在VS中为64字节,在VC中和VS不同,只好先看看内存到底是怎么分配的了:

    首先:

    基本常识:
    1 栈向低地址稳定增长,其空间在编译时确定,调用函数时分配,不能动态分配;堆中可动态分配空间,每一次分配都会
    优先分配低地址空间,如果低地址空间实在没有合适的可用空间,则在高地址空间分配。
    2 调用函数时的参数,是从右向左依次压入栈,换句话说,第一个参数,最后被压入栈,第一个弹出栈。
    3 测试了一下,栈底的存的是0xCCCCCCCC,大概就是传说中的安全间隔区中的数据。
    其次:

    新发现:
    1 关于每一个函数的栈空间大小:
    一个函数被调用的时候,系统就会分配给它的函数体中所申请的空间,并不是等到函数执行到变量声明的时候再去分配栈
    空间。换句话说,一个函数所占的栈空间,在它编译的时候已经确定,在它被调用的一刻起全部分配到位,其栈空间由函
    数体中的变量数目和大小所决定,还受到编译器的影响。当函数A调用函数B的时候,B的栈底地址,不受B在A中的被调用
    的位置的影响,即:A刚开始的时候调用B和A快结束的时候调用B,B的栈底位置相同,因为A所占的栈空间是固定的,函数
    B没有往A的栈中写数据的机会。
    最后这一句话是关键:一个子函数,没有机会往父函数的栈中写数据。
    另外:
    在VS的测试中,控制台程序的主函数的栈底地址接近于0x0012FE98,约1.187MB
    在VC的测试中,控制台程序的主函数的栈底地址接近于0x0012FF30,约1.187MB,相差大约100字节
    子函数的栈底地址随着主函数体中变量的增加而减小。
    2 栈中局部变量所占用的空间:
    在VS的栈中,在设定1字节对齐的情况下,在VS的栈中,相邻两个int, char, unsigned int, void* 等局部变量的地址间
    隔也是12字节,经测试,只有最低地址用来存储数据,高地址的所有字节都用0xCC填充;
    在VC的栈中,同样设定1字节对齐,相邻两个int的地址间隔为4字节,相邻两个char的地址间隔也是4字节。
    两种编译器都无视1字节对齐编译命令,而且VS中的几种基本类型变量竟然都占12字节,其sizeof(int)明明是4字节。
    在VS中,子函数的int和char类型的参数在其栈中占的空间都是4字节。
    3 安全间隔区的大小:
    在VS中,主函数的栈顶元素地址和子函数栈底地址,相差220字节
    在VC中,主函数的栈顶元素地址和子函数栈底地址,相差84字节
    4 连续分配堆空间时,若低地址没有可用空间,则分配地址往后移的距离:
    在VS中,每一次分配堆内存会导致堆内存地址至少后移64字节,并以8字节为单位增长,计算公式是:设申请的空间大小
    为N字节,则在本次分配完成之后,堆内存地址后移ceil((N+60)/8)*8字节,例如,申请93字节内存时,实际地址将后移
    ceil((99+60)/8)*8 = 20*8 = 160字节。
    在VC中,后移地址最小为56字节,并以16字节为单位增长,计算公式是:ceil((N-12)/16)*16+56,例如,申请192字节内
    存是,实际地址后移ceil((192-12)/16)*16+56 = 12*16+56 = 248。
    以上后移地址还会受到具体执行环境的影响,以上计算出来的是后移距离的最小值,有时会出现大距离的后移,之后又恢
    复满足以上算法的后移,
    5 什么叫合适的可用空间:
    经测试,每次动态申请内存时,会按4中的算法去计算出一个空间,如VS中会计算M = ceil((N+60)/8)*8,堆中满足等于M
    的最低地址的空间为合适的可用空间,将会被分配,如果没有等于M的内存空间,则大于M的最低地址空间为合适的可用空
    间,将会被分配。
    6 被调用的函数带参数时:
    参数的栈空间和子函数的栈空间之间有8字节的间隔,这应该是存储跳转地址的位置,在一次测试中,参数空间的栈顶方
    向, 有8字节的指令地址,参数空间的栈底方向有12字节的数据,其中栈最底端的8字节类似于指令地址。
    以上就是我根据实验的结果作出的一些理解。

    VS代码:

      1 #include <stdlib.h>
      2 #include <math.h>
      3 
      4 #pragma pack(1)
      5 
      6 bool flag = false;
      7 void* q = NULL;
      8 void print_adress(void* p, int mode = 0)
      9 {
     10 
     11     unsigned int adress = (unsigned int)p;
     12     int cnt = 8;
     13     char str[11];
     14     str[0] = '0';
     15     str[1] = 'x';
     16     str[10] = 0;
     17     while (cnt)
     18     {
     19         int tmp = adress%16;
     20         adress >>= 4;
     21         str[1+cnt] = tmp<10?(tmp+'0'):(tmp-10+'A');
     22         cnt--;
     23     }
     24     if(mode == 3)
     25     {
     26         printf("	%s
    ", str);
     27         return;
     28     }
     29     if(flag)
     30         printf("%s,和上一地址的距离为:%d字节
    ", str, abs((char*)p-(char*)q));
     31     else 
     32     {
     33         printf("%s
    ", str, abs((char*)p-(char*)q));
     34         flag = !flag;
     35     }
     36 
     37     q = p;
     38 }
     39 
     40 template <class T>
     41 void stack_memory_type()
     42 {
     43     flag = false;
     44     T i;
     45     T j;
     46     T k;
     47     print_adress((void*)&i);        // 在栈中申请的空间始终是连续的
     48     print_adress((void*)&j);
     49     print_adress((void*)&k);
     50     printf("
    ");
     51 }
     52 
     53 template <class T>
     54 void stack_memory_parameter(T i, T j , T k)
     55 {
     56     flag = false;
     57     T m;
     58     T n;
     59 
     60     print_adress((void*)&k);        // 参数是从右往左依次入栈的!从结果可以看出来!
     61     print_adress((void*)&j);
     62     print_adress((void*)&i);
     63 
     64     print_adress((void*)&m);
     65     print_adress((void*)&n);
     66     printf("
    ");
     67 }
     68 
     69 void other_test_of_stack(char C)
     70 {
     71     int T = C;
     72     char O = C;
     73     unsigned int P = (unsigned int)&C;
     74     char* Q;
     75     Q = (char*)&Q;
     76     printf(">> 变量Q之前的内容是:
    ");
     77     printf("变量Q");
     78     print_adress((void*)*(unsigned int*)Q, 3);
     79     Q += 4;
     80     printf("");
     81     print_adress((void*)*(unsigned int*)Q, 3);
     82     Q += 4;
     83     printf("");
     84     print_adress((void*)*(unsigned int*)Q, 3);
     85     Q += 4;
     86     printf("变量P");
     87     print_adress((void*)*(unsigned int*)Q, 3);
     88     Q += 4;
     89     printf("");
     90     print_adress((void*)*(unsigned int*)Q, 3);
     91     Q += 4;
     92     printf("");
     93     print_adress((void*)*(unsigned int*)Q, 3);
     94     Q += 4;
     95     printf("变量O");
     96     print_adress((void*)*(unsigned int*)Q, 3);
     97     printf("	可以看出来变量O只占用了第一个字节Ox07,后面的字节填充0xCCCCCC
    ");
     98     Q += 4;
     99     printf("");
    100     print_adress((void*)*(unsigned int*)Q, 3);
    101     Q += 4;
    102     printf("");
    103     print_adress((void*)*(unsigned int*)Q, 3);
    104     Q += 4;
    105     printf("变量T");
    106     print_adress((void*)*(unsigned int*)Q, 3);
    107     Q += 4;
    108     printf("");
    109     print_adress((void*)*(unsigned int*)Q, 3);
    110     Q += 4;
    111     printf("?");
    112     print_adress((void*)*(unsigned int*)Q, 3);
    113     Q += 4;
    114     printf("?");
    115     print_adress((void*)*(unsigned int*)Q, 3);
    116     Q += 4;
    117     printf("参数C");
    118     print_adress((void*)*(unsigned int*)Q, 3);
    119     Q += 4;
    120     printf("?");
    121     print_adress((void*)*(unsigned int*)Q, 3);
    122     Q += 4;
    123     printf("?");
    124     print_adress((void*)*(unsigned int*)Q, 3);
    125     Q += 4;
    126     printf("?");
    127     print_adress((void*)*(unsigned int*)Q, 3);
    128     Q += 4;
    129     printf("");
    130     print_adress((void*)*(unsigned int*)Q, 3);
    131     Q += 4;
    132     printf("");
    133     print_adress((void*)*(unsigned int*)Q, 3);
    134     Q += 4;
    135     printf("");
    136     print_adress((void*)*(unsigned int*)Q, 3);
    137     Q += 4;
    138     printf("");
    139     print_adress((void*)*(unsigned int*)Q, 3);
    140     printf("空表示未初始化,也未利用的空间,打问号的应该是一些指令
    
    ");
    141 
    142 }
    143 
    144 
    145 void new_heap_memory(int n)
    146 {
    147     if(n < 1)
    148         return;
    149     char* p_first = new char[n];
    150     char* p_second = new char[1];
    151     int offset = (char*)p_second - (char*)p_first;
    152     int m = (int)ceil(((double)n+60.0)/8.0)*8;
    153     printf(">> N = %4d字节,M = %4d字节,OFFSET = %4d字节
    ", n, m, offset);
    154     if(m < offset)
    155         printf(">> OFFSET > M,本块内存是从低地址空间“捡”到的大于等于64字节的空间
    					其实就是p1指向的那块64字节空间
    ");
    156     else if(offset < 0)
    157         printf(">> OFFSET < 0,说明低地址空间有且只有小于%4d字节,且大于等于64字节的空间
    ", m);
    158     else
    159         printf(">> OFFSET = M,说明低地址空间合适的可用空间
    ");
    160     delete p_first;
    161     delete p_second;
    162 }
    163 
    164 void malloc_heap_memory(int n)
    165 {
    166     if(n < 1)
    167         return;
    168     void* p_first = malloc(n);
    169     void* p_second = malloc(1);
    170 
    171     int offset = (char*)p_second - (char*)p_first;
    172     int m = (int)ceil(((double)n+60.0)/8.0)*8;
    173     printf(">> N = %4d字节,M = %4d字节,OFFSET = %4d字节
    ", n, m, offset);
    174     if(m < offset)
    175         printf(">> OFFSET > M,本块内存是从低地址空间“捡”到的大于等于64字节的空间
    					其实就是p1指向的那块64字节空间
    ");
    176     else if(offset < 0)
    177         printf(">> OFFSET < 0,说明低地址空间有且只有小于%4d字节,且大于等于64字节的空间
    ", m);
    178     else
    179         printf(">> OFFSET = M,说明低地址空间合适的可用空间
    ");
    180     free(p_first);
    181     free(p_second);
    182 }
    183 
    184 int main()
    185 {
    186     printf(">> 3个栈中的int
    ");
    187     stack_memory_type<int>();
    188     
    189     printf(">> 3个栈中的char
    ");
    190     stack_memory_type<char>();
    191 
    192     int* p_i = 0;
    193     int* p_j = 0;
    194     int* p_k = 0;
    195     int i = 0, j = 0, k = 0;
    196     char a = 0, b = 0, c = 0;
    197     p_i = &i;
    198     p_j = &j;
    199     p_k = &k;
    200 
    201     flag = false;
    202     printf(">> 主函数中3个int的地址
    ");
    203     print_adress((void*)p_i);        // 这3个空间是连续的
    204     print_adress((void*)p_j);
    205     print_adress((void*)p_k);    
    206     printf("
    ");
    207 
    208     // 主函数中占用了3个指针和3个int的空间,但是被调用函数中的变量在栈中的起始地址并没有发生变化
    209     // 原因是主函数的栈大小在编译时已经确定
    210     printf(">> 主函数中占有3个int空间之后,3个被调用函数栈中的int
    ");
    211     stack_memory_type<int>();
    212     printf(">> 主函数中占有3个int空间之后,3个被调用函数栈中的char
    ");
    213     stack_memory_type<char>();
    214 
    215     // 被调用的函数带参数的时候
    216     printf(">> 被调用函数栈中的3个int参数,和2个int
    ");
    217     stack_memory_parameter(i, j, k);
    218 
    219     printf(">> 被调用函数栈中的3个char参数,和2个char
    ");
    220     stack_memory_parameter(a, b, c);
    221 
    222     printf(">> 看看栈里都存了些什么
    ");
    223     other_test_of_stack(char(7));
    224         
    225     printf(">> 没有其他的动态分配空间的情况下:
    ");
    226     printf(">> 使用new申请一定字节的空间的情况,malloc也是一样
    ");
    227     for(int cnt1 = 1; cnt1 <= 1024; cnt1 <<= 2)
    228         new_heap_memory(cnt1);
    229     printf("
    ");
    230 
    231     printf(">> 有动态分配空间,不完全释放,造成空闲堆空间分散的情况下:
    ");
    232 
    233     char* p1 = new char[1];
    234     char* p2 = new char[1];
    235     char* p3 = new char[1];
    236 
    237     delete p1;
    238 
    239     printf(">> 使用new申请一定字节的空间的情况,malloc也是一样
    ");
    240     for(int cnt2 = 1; cnt2 <= 1024; cnt2 <<= 2)
    241         new_heap_memory(cnt2);
    242     printf("
    ");
    243 
    244     delete p2;
    245     delete p3;
    246     system("pause");
    247     return 0;
    248 }

    VS输出:

    >> 3个栈中的int
    0x0012FD9C
    0x0012FD90,和上一地址的距离为:12字节
    0x0012FD84,和上一地址的距离为:12字节
    
    >> 3个栈中的char
    0x0012FD9F
    0x0012FD93,和上一地址的距离为:12字节
    0x0012FD87,和上一地址的距离为:12字节
    
    >> 主函数中3个int的地址
    0x0012FF3C
    0x0012FF30,和上一地址的距离为:12字节
    0x0012FF24,和上一地址的距离为:12字节
    
    >> 主函数中占有3个int空间之后,3个被调用函数栈中的int
    0x0012FD9C
    0x0012FD90,和上一地址的距离为:12字节
    0x0012FD84,和上一地址的距离为:12字节
    
    >> 主函数中占有3个int空间之后,3个被调用函数栈中的char
    0x0012FD9F
    0x0012FD93,和上一地址的距离为:12字节
    0x0012FD87,和上一地址的距离为:12字节
    
    >> 被调用函数栈中的3个int参数,和2个int
    0x0012FDA8
    0x0012FDA4,和上一地址的距离为:4字节
    0x0012FDA0,和上一地址的距离为:4字节
    0x0012FD90,和上一地址的距离为:16字节
    0x0012FD84,和上一地址的距离为:12字节
    
    >> 被调用函数栈中的3个char参数,和2个char
    0x0012FDA8
    0x0012FDA4,和上一地址的距离为:4字节
    0x0012FDA0,和上一地址的距离为:4字节
    0x0012FD93,和上一地址的距离为:13字节
    0x0012FD87,和上一地址的距离为:12字节
    
    >> 看看栈里都存了些什么
    >> 变量Q之前的内容是:
    变量Q   0x0012FD740xCCCCCCCC0xCCCCCCCC
    变量P   0x0012FDA80xCCCCCCCC0xCCCCCCCC
    变量O   0x07CCCCCC
            可以看出来变量O只占用了第一个字节Ox07,后面的字节填充0xCCCCCC
    空      0xCCCCCCCC0xCCCCCCCC
    变量T   0x000000070xCCCCCCCC
    ?       0x0012FF68
    ?       0x0041212C
    参数C   0x00000007
    ?       0x00000020
    ?       0x06CDF9D0
    ?       0x7FFD80000xCCCCCCCC0xCCCCCCCC0xCCCCCCCC0xCCCCCCCC
    空表示未初始化,也未利用的空间,打问号的应该是一些指令
    
    >> 没有其他的动态分配空间的情况下:
    >> 使用new申请一定字节的空间的情况,malloc也是一样
    >> N =    1字节,M =   64字节,OFFSET =   64字节
    >> OFFSET = M,说明低地址空间合适的可用空间
    >> N =    4字节,M =   64字节,OFFSET =   64字节
    >> OFFSET = M,说明低地址空间合适的可用空间
    >> N =   16字节,M =   80字节,OFFSET =   80字节
    >> OFFSET = M,说明低地址空间合适的可用空间
    >> N =   64字节,M =  128字节,OFFSET =  128字节
    >> OFFSET = M,说明低地址空间合适的可用空间
    >> N =  256字节,M =  320字节,OFFSET =  320字节
    >> OFFSET = M,说明低地址空间合适的可用空间
    >> N = 1024字节,M = 1088字节,OFFSET = 1088字节
    >> OFFSET = M,说明低地址空间合适的可用空间
    
    >> 有动态分配空间,不完全释放,造成空闲堆空间分散的情况下:
    >> 使用new申请一定字节的空间的情况,malloc也是一样
    >> N =    1字节,M =   64字节,OFFSET =  192字节
    >> OFFSET > M,本块内存是从低地址空间“捡”到的大于等于64字节的空间
                                            其实就是p1指向的那块64字节空间
    >> N =    4字节,M =   64字节,OFFSET =  192字节
    >> OFFSET > M,本块内存是从低地址空间“捡”到的大于等于64字节的空间
                                            其实就是p1指向的那块64字节空间
    >> N =   16字节,M =   80字节,OFFSET = -192字节
    >> OFFSET < 0,说明低地址空间有且只有小于  80字节,且大于等于64字节的空间
    >> N =   64字节,M =  128字节,OFFSET = -192字节
    >> OFFSET < 0,说明低地址空间有且只有小于 128字节,且大于等于64字节的空间
    >> N =  256字节,M =  320字节,OFFSET = -192字节
    >> OFFSET < 0,说明低地址空间有且只有小于 320字节,且大于等于64字节的空间
    >> N = 1024字节,M = 1088字节,OFFSET = -192字节
    >> OFFSET < 0,说明低地址空间有且只有小于1088字节,且大于等于64字节的空间
    
    请按任意键继续. . .

    VC代码:

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <math.h>
      4 
      5 #pragma pack(1)
      6 
      7 bool flag = false;
      8 void* q = NULL;
      9 void print_adress(void* p, int mode = 0)
     10 {
     11 
     12     unsigned int adress = (unsigned int)p;
     13     int cnt = 8;
     14     char str[11];
     15     str[0] = '0';
     16     str[1] = 'x';
     17     str[10] = 0;
     18     while (cnt)
     19     {
     20         int tmp = adress%16;
     21         adress >>= 4;
     22         str[1+cnt] = tmp<10?(tmp+'0'):(tmp-10+'A');
     23         cnt--;
     24     }
     25     if(mode == 3)
     26     {
     27         printf("	%s
    ", str);
     28         return;
     29     }
     30     if(flag)
     31         printf("%s,和上一地址的距离为:%d字节
    ", str, abs((char*)p-(char*)q));
     32     else 
     33     {
     34         printf("%s
    ", str, abs((char*)p-(char*)q));
     35         flag = !flag;
     36     }
     37 
     38     q = p;
     39 }
     40 
     41 template <class T>
     42 void stack_memory_type()
     43 {
     44     flag = false;
     45     T i;
     46     T j;
     47     T k;
     48     print_adress((void*)&i);        // 在栈中申请的空间始终是连续的
     49     print_adress((void*)&j);
     50     print_adress((void*)&k);
     51     printf("
    ");
     52 }
     53 
     54 template <class T>
     55 void stack_memory_parameter(T i, T j , T k)
     56 {
     57     flag = false;
     58     T m;
     59     T n;
     60 
     61     print_adress((void*)&k);        // 参数是从右往左依次入栈的!从结果可以看出来!
     62     print_adress((void*)&j);
     63     print_adress((void*)&i);
     64 
     65     print_adress((void*)&m);
     66     print_adress((void*)&n);
     67     printf("
    ");
     68 }
     69 
     70 void other_test_of_stack(char C)
     71 {
     72     int T = C;
     73     char O = C;
     74     unsigned int P = (unsigned int)&C;
     75     char* Q;
     76     Q = (char*)&Q;
     77     printf(">> 变量Q之前的内容是:
    ");
     78     printf("变量Q");
     79     print_adress((void*)*(unsigned int*)Q, 3);
     80     Q += 4;
     81     printf("变量P");
     82     print_adress((void*)*(unsigned int*)Q, 3);
     83     Q += 4;
     84     printf("变量O");
     85     print_adress((void*)*(unsigned int*)Q, 3);
     86     printf("	可以看出来变量O只占用了最后一个个字节Ox07,前面的字节填充0xCCCCCC
    ");
     87     Q += 4;
     88     printf("变量T");
     89     print_adress((void*)*(unsigned int*)Q, 3);
     90     Q += 4;
     91     printf("?");
     92     print_adress((void*)*(unsigned int*)Q, 3);
     93     Q += 4;
     94     printf("?");
     95     print_adress((void*)*(unsigned int*)Q, 3);
     96     Q += 4;
     97     printf("参数C");
     98     print_adress((void*)*(unsigned int*)Q, 3);
     99     Q += 4;
    100     printf("?");
    101     print_adress((void*)*(unsigned int*)Q, 3);
    102     Q += 4;
    103     printf("?");
    104     print_adress((void*)*(unsigned int*)Q, 3);
    105     Q += 4;
    106     printf("?");
    107     print_adress((void*)*(unsigned int*)Q, 3);
    108     Q += 4;
    109     printf("");
    110     print_adress((void*)*(unsigned int*)Q, 3);
    111     Q += 4;
    112     printf("");
    113     print_adress((void*)*(unsigned int*)Q, 3);
    114     printf("空表示未初始化,也未利用的空间,打问号的应该是一些指令
    
    ");
    115 
    116 }
    117 
    118 
    119 void new_heap_memory(int n)
    120 {
    121     if(n < 1)
    122         return;
    123     char* p_first = new char[n];
    124     char* p_second = new char[1];
    125     int offset = (char*)p_second - (char*)p_first;
    126     int m = (int)ceil(((double)n-12)/16.0)*16+56;
    127     printf(">> N = %4d字节,M = %4d字节,OFFSET = %4d字节
    ", n, m, offset);
    128     if(m < offset)
    129         printf(">> OFFSET > M,本块内存是从低地址空间“捡”到的大于等于56字节的空间
    					其实就是p1指向的那块56字节空间
    ");
    130     else if(offset < 0)
    131         printf(">> OFFSET < 0,低地址空间有且只有小于%4d字节,且大于等于56字节的空间
    ", m);
    132     else
    133         printf(">> OFFSET = M,说明低地址空间合适的可用空间
    ");
    134     delete p_first;
    135     delete p_second;
    136 }
    137 
    138 void malloc_heap_memory(int n)
    139 {
    140     if(n < 1)
    141         return;
    142     void* p_first = malloc(n);
    143     void* p_second = malloc(1);
    144 
    145     int offset = (char*)p_second - (char*)p_first;
    146     int m = (int)ceil(((double)n-12)/16.0)*16+56;
    147     printf(">> N = %4d字节,M = %4d字节,OFFSET = %4d字节
    ", n, m, offset);
    148     if(m < offset)
    149         printf(">> OFFSET > M,本块内存是从低地址空间“捡”到的大于等于56字节的空间
    					其实就是p1指向的那块56字节空间
    ");
    150     else if(offset < 0)
    151         printf(">> OFFSET < 0,低地址空间有且只有小于%4d字节,且大于等于56字节的空间
    ", m);
    152     else
    153         printf(">> OFFSET = M,说明低地址空间合适的可用空间
    ");
    154     free(p_first);
    155     free(p_second);
    156 }
    157 
    158 int main()
    159 {
    160     printf(">> 3个栈中的int
    ");
    161     stack_memory_type<int>();
    162     
    163     printf(">> 3个栈中的char
    ");
    164     stack_memory_type<char>();
    165 
    166     int* p_i = 0;
    167     int* p_j = 0;
    168     int* p_k = 0;
    169     int i = 0, j = 0, k = 0;
    170     char a = 0, b = 0, c = 0;
    171     p_i = &i;
    172     p_j = &j;
    173     p_k = &k;
    174 
    175     flag = false;
    176     printf(">> 主函数中3个int的地址
    ");
    177     print_adress((void*)p_i);        // 这3个空间是连续的
    178     print_adress((void*)p_j);
    179     print_adress((void*)p_k);    
    180     printf("
    ");
    181 
    182     // 主函数中占用了3个指针和3个int的空间,但是被调用函数中的变量在栈中的起始地址并没有发生变化
    183     // 原因是主函数的栈大小在编译时已经确定
    184     printf(">> 主函数中占有3个int空间之后,3个被调用函数栈中的int
    ");
    185     stack_memory_type<int>();
    186     printf(">> 主函数中占有3个int空间之后,3个被调用函数栈中的char
    ");
    187     stack_memory_type<char>();
    188 
    189     // 被调用的函数带参数的时候
    190     printf(">> 被调用函数栈中的3个int参数,和2个int
    ");
    191     stack_memory_parameter(i, j, k);
    192 
    193     printf(">> 被调用函数栈中的3个char参数,和2个char
    ");
    194     stack_memory_parameter(a, b, c);
    195 
    196     printf(">> 看看栈里都存了些什么
    ");
    197     other_test_of_stack(char(7));
    198         
    199     printf(">> 没有其他的动态分配空间的情况下:
    ");
    200     printf(">> 使用new申请一定字节的空间的情况,malloc也是一样
    ");
    201     for(int cnt1 = 1; cnt1 <= 1024; cnt1 <<= 2)
    202         new_heap_memory(cnt1);
    203     printf("
    ");
    204 
    205     printf(">> 有动态分配空间,不完全释放,造成空闲堆空间分散的情况下:
    ");
    206 
    207     char* p1 = new char[1];
    208     char* p2 = new char[1];
    209     char* p3 = new char[1];
    210 
    211     delete p1;
    212 
    213     printf(">> 使用new申请一定字节的空间的情况,malloc也是一样
    ");
    214     for(int cnt2 = 1; cnt2 <= 1024; cnt2 <<= 2)
    215         new_heap_memory(cnt2);
    216     printf("
    ");
    217 
    218     system("pause");
    219     return 0;
    220 }

    VC输出:

    >> 3个栈中的int
    0x0012FEE0
    0x0012FEDC,和上一地址的距离为:4字节
    0x0012FED8,和上一地址的距离为:4字节
    
    >> 3个栈中的char
    0x0012FEE0
    0x0012FEDC,和上一地址的距离为:4字节
    0x0012FED8,和上一地址的距离为:4字节
    
    >> 主函数中3个int的地址
    0x0012FF70
    0x0012FF6C,和上一地址的距离为:4字节
    0x0012FF68,和上一地址的距离为:4字节
    
    >> 主函数中占有3个int空间之后,3个被调用函数栈中的int
    0x0012FEE0
    0x0012FEDC,和上一地址的距离为:4字节
    0x0012FED8,和上一地址的距离为:4字节
    
    >> 主函数中占有3个int空间之后,3个被调用函数栈中的char
    0x0012FEE0
    0x0012FEDC,和上一地址的距离为:4字节
    0x0012FED8,和上一地址的距离为:4字节
    
    >> 被调用函数栈中的3个int参数,和2个int
    0x0012FEE8
    0x0012FEE4,和上一地址的距离为:4字节
    0x0012FEE0,和上一地址的距离为:4字节
    0x0012FED4,和上一地址的距离为:12字节
    0x0012FED0,和上一地址的距离为:4字节
    
    >> 被调用函数栈中的3个char参数,和2个char
    0x0012FEE8
    0x0012FEE4,和上一地址的距离为:4字节
    0x0012FEE0,和上一地址的距离为:4字节
    0x0012FED4,和上一地址的距离为:12字节
    0x0012FED0,和上一地址的距离为:4字节
    
    >> 看看栈里都存了些什么
    >> 变量Q之前的内容是:
    变量Q   0x0012FED0
    变量P   0x0012FEE8
    变量O   0xCCCCCC07
            可以看出来变量O只占用了最后一个个字节Ox07,前面的字节填充0xCCCCCC
    变量T   0x00000007
    ?       0x0012FF80
    ?       0x0040184F
    参数C   0x00000007
    ?       0x00241FE4
    ?       0x0012F7BC
    ?       0x7FFD80000xCCCCCCCC0xCCCCCCCC
    空表示未初始化,也未利用的空间,打问号的应该是一些指令
    
    >> 没有其他的动态分配空间的情况下:
    >> 使用new申请一定字节的空间的情况,malloc也是一样
    >> N =    1字节,M =   56字节,OFFSET =   56字节
    >> OFFSET = M,说明低地址空间合适的可用空间
    >> N =    4字节,M =   56字节,OFFSET =   56字节
    >> OFFSET = M,说明低地址空间合适的可用空间
    >> N =   16字节,M =   72字节,OFFSET =   72字节
    >> OFFSET = M,说明低地址空间合适的可用空间
    >> N =   64字节,M =  120字节,OFFSET =  120字节
    >> OFFSET = M,说明低地址空间合适的可用空间
    >> N =  256字节,M =  312字节,OFFSET = -9096字节
    >> OFFSET < 0,低地址空间有且只有小于 312字节,且大于等于56字节的空间
    >> N = 1024字节,M = 1080字节,OFFSET = -9096字节
    >> OFFSET < 0,低地址空间有且只有小于1080字节,且大于等于56字节的空间
    
    >> 有动态分配空间,不完全释放,造成空闲堆空间分散的情况下:
    >> 使用new申请一定字节的空间的情况,malloc也是一样
    >> N =    1字节,M =   56字节,OFFSET =  168字节
    >> OFFSET > M,本块内存是从低地址空间“捡”到的大于等于56字节的空间
                                            其实就是p1指向的那块56字节空间
    >> N =    4字节,M =   56字节,OFFSET =  168字节
    >> OFFSET > M,本块内存是从低地址空间“捡”到的大于等于56字节的空间
                                            其实就是p1指向的那块56字节空间
    >> N =   16字节,M =   72字节,OFFSET = -168字节
    >> OFFSET < 0,低地址空间有且只有小于  72字节,且大于等于56字节的空间
    >> N =   64字节,M =  120字节,OFFSET = -9096字节
    >> OFFSET < 0,低地址空间有且只有小于 120字节,且大于等于56字节的空间
    >> N =  256字节,M =  312字节,OFFSET = -9096字节
    >> OFFSET < 0,低地址空间有且只有小于 312字节,且大于等于56字节的空间
    >> N = 1024字节,M = 1080字节,OFFSET = -9096字节
    >> OFFSET < 0,低地址空间有且只有小于1080字节,且大于等于56字节的空间
    
    请按任意键继续. . .
  • 相关阅读:
    python里面的xlrd模块详解以及样例
    关于DOM的事件操作
    python正则表达式去除文本中间的换行符
    文本分类问题汇总
    pip安装问题
    3NF的无损连接和保持函数依赖的分解、BCNF的无损连接的分解
    Pyhton基本图形绘制
    软件过程模型
    常见算法的时间与空间复杂度
    随笔
  • 原文地址:https://www.cnblogs.com/zanzan101/p/3346562.html
Copyright © 2020-2023  润新知