学习堆与栈内存分配方式
本来想用对和栈的空间分配方法去实现类似于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("\t%s\n", str); 27 return; 28 } 29 if(flag) 30 printf("%s,和上一地址的距离为:%d字节\n", str, abs((char*)p-(char*)q)); 31 else 32 { 33 printf("%s\n", 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("\n"); 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("\n"); 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之前的内容是:\n"); 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("\t可以看出来变量O只占用了第一个字节Ox07,后面的字节填充0xCCCCCC\n"); 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("空表示未初始化,也未利用的空间,打问号的应该是一些指令\n\n"); 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", n, m, offset); 154 if(m < offset) 155 printf(">> OFFSET > M,本块内存是从低地址空间“捡”到的大于等于64字节的空间\n\t\t\t\t\t其实就是p1指向的那块64字节空间\n"); 156 else if(offset < 0) 157 printf(">> OFFSET < 0,说明低地址空间有且只有小于%4d字节,且大于等于64字节的空间\n", m); 158 else 159 printf(">> OFFSET = M,说明低地址空间合适的可用空间\n"); 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", n, m, offset); 174 if(m < offset) 175 printf(">> OFFSET > M,本块内存是从低地址空间“捡”到的大于等于64字节的空间\n\t\t\t\t\t其实就是p1指向的那块64字节空间\n"); 176 else if(offset < 0) 177 printf(">> OFFSET < 0,说明低地址空间有且只有小于%4d字节,且大于等于64字节的空间\n", m); 178 else 179 printf(">> OFFSET = M,说明低地址空间合适的可用空间\n"); 180 free(p_first); 181 free(p_second); 182 } 183 184 int main() 185 { 186 printf(">> 3个栈中的int\n"); 187 stack_memory_type<int>(); 188 189 printf(">> 3个栈中的char\n"); 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的地址\n"); 203 print_adress((void*)p_i); // 这3个空间是连续的 204 print_adress((void*)p_j); 205 print_adress((void*)p_k); 206 printf("\n"); 207 208 // 主函数中占用了3个指针和3个int的空间,但是被调用函数中的变量在栈中的起始地址并没有发生变化 209 // 原因是主函数的栈大小在编译时已经确定 210 printf(">> 主函数中占有3个int空间之后,3个被调用函数栈中的int\n"); 211 stack_memory_type<int>(); 212 printf(">> 主函数中占有3个int空间之后,3个被调用函数栈中的char\n"); 213 stack_memory_type<char>(); 214 215 // 被调用的函数带参数的时候 216 printf(">> 被调用函数栈中的3个int参数,和2个int\n"); 217 stack_memory_parameter(i, j, k); 218 219 printf(">> 被调用函数栈中的3个char参数,和2个char\n"); 220 stack_memory_parameter(a, b, c); 221 222 printf(">> 看看栈里都存了些什么\n"); 223 other_test_of_stack(char(7)); 224 225 printf(">> 没有其他的动态分配空间的情况下:\n"); 226 printf(">> 使用new申请一定字节的空间的情况,malloc也是一样\n"); 227 for(int cnt1 = 1; cnt1 <= 1024; cnt1 <<= 2) 228 new_heap_memory(cnt1); 229 printf("\n"); 230 231 printf(">> 有动态分配空间,不完全释放,造成空闲堆空间分散的情况下:\n"); 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也是一样\n"); 240 for(int cnt2 = 1; cnt2 <= 1024; cnt2 <<= 2) 241 new_heap_memory(cnt2); 242 printf("\n"); 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 0x0012FD74 空 0xCCCCCCCC 空 0xCCCCCCCC 变量P 0x0012FDA8 空 0xCCCCCCCC 空 0xCCCCCCCC 变量O 0x07CCCCCC 可以看出来变量O只占用了第一个字节Ox07,后面的字节填充0xCCCCCC 空 0xCCCCCCCC 空 0xCCCCCCCC 变量T 0x00000007 空 0xCCCCCCCC ? 0x0012FF68 ? 0x0041212C 参数C 0x00000007 ? 0x00000020 ? 0x06CDF9D0 ? 0x7FFD8000 空 0xCCCCCCCC 空 0xCCCCCCCC 空 0xCCCCCCCC 空 0xCCCCCCCC 空表示未初始化,也未利用的空间,打问号的应该是一些指令 >> 没有其他的动态分配空间的情况下: >> 使用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("\t%s\n", str); 28 return; 29 } 30 if(flag) 31 printf("%s,和上一地址的距离为:%d字节\n", str, abs((char*)p-(char*)q)); 32 else 33 { 34 printf("%s\n", 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("\n"); 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("\n"); 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之前的内容是:\n"); 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("\t可以看出来变量O只占用了最后一个个字节Ox07,前面的字节填充0xCCCCCC\n"); 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("空表示未初始化,也未利用的空间,打问号的应该是一些指令\n\n"); 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", n, m, offset); 128 if(m < offset) 129 printf(">> OFFSET > M,本块内存是从低地址空间“捡”到的大于等于56字节的空间\n\t\t\t\t\t其实就是p1指向的那块56字节空间\n"); 130 else if(offset < 0) 131 printf(">> OFFSET < 0,低地址空间有且只有小于%4d字节,且大于等于56字节的空间\n", m); 132 else 133 printf(">> OFFSET = M,说明低地址空间合适的可用空间\n"); 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", n, m, offset); 148 if(m < offset) 149 printf(">> OFFSET > M,本块内存是从低地址空间“捡”到的大于等于56字节的空间\n\t\t\t\t\t其实就是p1指向的那块56字节空间\n"); 150 else if(offset < 0) 151 printf(">> OFFSET < 0,低地址空间有且只有小于%4d字节,且大于等于56字节的空间\n", m); 152 else 153 printf(">> OFFSET = M,说明低地址空间合适的可用空间\n"); 154 free(p_first); 155 free(p_second); 156 } 157 158 int main() 159 { 160 printf(">> 3个栈中的int\n"); 161 stack_memory_type<int>(); 162 163 printf(">> 3个栈中的char\n"); 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的地址\n"); 177 print_adress((void*)p_i); // 这3个空间是连续的 178 print_adress((void*)p_j); 179 print_adress((void*)p_k); 180 printf("\n"); 181 182 // 主函数中占用了3个指针和3个int的空间,但是被调用函数中的变量在栈中的起始地址并没有发生变化 183 // 原因是主函数的栈大小在编译时已经确定 184 printf(">> 主函数中占有3个int空间之后,3个被调用函数栈中的int\n"); 185 stack_memory_type<int>(); 186 printf(">> 主函数中占有3个int空间之后,3个被调用函数栈中的char\n"); 187 stack_memory_type<char>(); 188 189 // 被调用的函数带参数的时候 190 printf(">> 被调用函数栈中的3个int参数,和2个int\n"); 191 stack_memory_parameter(i, j, k); 192 193 printf(">> 被调用函数栈中的3个char参数,和2个char\n"); 194 stack_memory_parameter(a, b, c); 195 196 printf(">> 看看栈里都存了些什么\n"); 197 other_test_of_stack(char(7)); 198 199 printf(">> 没有其他的动态分配空间的情况下:\n"); 200 printf(">> 使用new申请一定字节的空间的情况,malloc也是一样\n"); 201 for(int cnt1 = 1; cnt1 <= 1024; cnt1 <<= 2) 202 new_heap_memory(cnt1); 203 printf("\n"); 204 205 printf(">> 有动态分配空间,不完全释放,造成空闲堆空间分散的情况下:\n"); 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也是一样\n"); 214 for(int cnt2 = 1; cnt2 <= 1024; cnt2 <<= 2) 215 new_heap_memory(cnt2); 216 printf("\n"); 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 ? 0x7FFD8000 空 0xCCCCCCCC 空 0xCCCCCCCC 空表示未初始化,也未利用的空间,打问号的应该是一些指令 >> 没有其他的动态分配空间的情况下: >> 使用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字节的空间 请按任意键继续. . .