本来想用对和栈的空间分配方法去实现类似于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 #include2 #include 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 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 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 else159 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 else179 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 ();188 189 printf(">> 3个栈中的char\n");190 stack_memory_type ();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 ();212 printf(">> 主函数中占有3个int空间之后,3个被调用函数栈中的char\n");213 stack_memory_type ();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个栈中的int0x0012FD9C0x0012FD90,和上一地址的距离为:12字节0x0012FD84,和上一地址的距离为:12字节>> 3个栈中的char0x0012FD9F0x0012FD93,和上一地址的距离为:12字节0x0012FD87,和上一地址的距离为:12字节>> 主函数中3个int的地址0x0012FF3C0x0012FF30,和上一地址的距离为:12字节0x0012FF24,和上一地址的距离为:12字节>> 主函数中占有3个int空间之后,3个被调用函数栈中的int0x0012FD9C0x0012FD90,和上一地址的距离为:12字节0x0012FD84,和上一地址的距离为:12字节>> 主函数中占有3个int空间之后,3个被调用函数栈中的char0x0012FD9F0x0012FD93,和上一地址的距离为:12字节0x0012FD87,和上一地址的距离为:12字节>> 被调用函数栈中的3个int参数,和2个int0x0012FDA80x0012FDA4,和上一地址的距离为:4字节0x0012FDA0,和上一地址的距离为:4字节0x0012FD90,和上一地址的距离为:16字节0x0012FD84,和上一地址的距离为:12字节>> 被调用函数栈中的3个char参数,和2个char0x0012FDA80x0012FDA4,和上一地址的距离为: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 #include2 #include 3 #include 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 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 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 else133 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 else153 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 ();162 163 printf(">> 3个栈中的char\n");164 stack_memory_type ();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 ();186 printf(">> 主函数中占有3个int空间之后,3个被调用函数栈中的char\n");187 stack_memory_type ();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个栈中的int0x0012FEE00x0012FEDC,和上一地址的距离为:4字节0x0012FED8,和上一地址的距离为:4字节>> 3个栈中的char0x0012FEE00x0012FEDC,和上一地址的距离为:4字节0x0012FED8,和上一地址的距离为:4字节>> 主函数中3个int的地址0x0012FF700x0012FF6C,和上一地址的距离为:4字节0x0012FF68,和上一地址的距离为:4字节>> 主函数中占有3个int空间之后,3个被调用函数栈中的int0x0012FEE00x0012FEDC,和上一地址的距离为:4字节0x0012FED8,和上一地址的距离为:4字节>> 主函数中占有3个int空间之后,3个被调用函数栈中的char0x0012FEE00x0012FEDC,和上一地址的距离为:4字节0x0012FED8,和上一地址的距离为:4字节>> 被调用函数栈中的3个int参数,和2个int0x0012FEE80x0012FEE4,和上一地址的距离为:4字节0x0012FEE0,和上一地址的距离为:4字节0x0012FED4,和上一地址的距离为:12字节0x0012FED0,和上一地址的距离为:4字节>> 被调用函数栈中的3个char参数,和2个char0x0012FEE80x0012FEE4,和上一地址的距离为: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字节的空间请按任意键继续. . .