学习堆与栈内存分配方式

本来想用对和栈的空间分配方法去实现类似于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字节的空间

请按任意键继续. . .
原文地址:https://www.cnblogs.com/zanzan101/p/3346562.html