一.程序内存分配
用C/C编译的程序消耗的内存分为以下几个部分。
1、堆栈区域(stack )编译器自动解除分配,存储函数的参数值、局部变量的值等。 那个
其行为类似于数据结构中的堆栈。
2、堆(heap )一般由程序员分配释放,如果程序员不释放,程序结束时OS可能会返回
我收下。 请注意,它与数据结构中的堆是不同的。 分配方法类似于链表。
3、全局领域(静态领域) (static ),全局变量和静态变量的容纳被汇总在一起,进行初始化
全局变量和静态变量位于一个区域,未初始化的全局变量和未初始化的静态变量位于相邻的其他区域
一个街区的区域。 -程序结束后,从系统中释放。
4、字符常数区域—常数字符串放在这里。 程序结束后系统被释放
5、程序代码区——存储函数体的二进制代码。
示例程序:
这是前辈写的,很详细
//main.cpp
int a=0 全局初始化区域
char *p1; 全局未初始化区域
main () )
{
int b; 堆栈
char s[]='abc '; 堆栈
char *p2; 堆栈
char *p3='123456 '; 123456 位于常数区,p3位于堆栈中。
静态输入c=0; 全局(静态)初始化区域
p1=(char* ) malloc ) 10;
p2=(char* ) malloc ) 20;
分配了10字节和20字节的区域位于堆中。
strcpy(P1,' 123456 ); 123456 位于常数区域,编译器将其与p3指向的' 123456 '和
优化为一个地方。
}
二.堆和堆的理论知识
2.1申请方式
stack:
系统自动分配。 例如,声明函数中的局部变量int b; 系统自动在堆栈中为b打开天空
伙伴
头儿:
程序员必须自己申请,指定大小,并在c中指定malloc函数
例如p1=(char* ) malloc ) 10;
在c中使用new运算符
例如p2=new char[10];
但是请注意,p1、p2本身位于堆栈中。
2.2
申请后系统的响应
堆栈:只要堆栈的剩余空间大于申请的空间,系统就会为程序提供内存。 否则,报告异常并告知堆栈溢出
出来。
堆:首先,必须知道操作系统中有记录可用内存地址的链表。 当系统收到计划申请时,
遍历此链表,查找第一个空间大于请求空间的堆节点,然后将该节点从空闲节点的链表中删除
中删除,并将该节点的空间指定给程序。 此外,在大多数系统中,此内存空间的
在起始地址中记录此次分配的大小,以便代码中的delete语句可以正确释放此内存空间。
另外,由于找到的堆节点的大小不一定等于申请的大小,所以系统会自动将多余的部分
重新定位到空的链表。
2.3申请大小限制
堆栈:在Windows上,堆栈是扩展到低地址的数据结构,是连续内存区域。 这句话的意思
堆栈顶部地址和最大堆栈容量是系统预先确定的,在WINDOWS上,堆栈大小为2米(2M )
的1M,总之是编译时确定的常数),如果申请的空间超过了堆栈的剩余空间
出示覆盖。 因此,从堆栈中得到的空间很小。
堆:堆是高地址扩展的数据结构,是不连续的内存区域。 这是因为系统保存在链表中
当然,空闲存储器地址是不连续的,但是链表的扫描方向是从低地址到高地址。 堆的大小
仅限于计算机系统中的有效虚拟内存。 由此可见,得到堆的空间比较灵活,比较大。
2.4申请效率比较:
堆栈由系统自动分配,速度很快。 但是程序员控制不了。
堆是由new分配的内存,一般速度较慢,容易出现内存碎片,但最容易使用
此外,在WINDOWS上,在VirtualAlloc中分配内存是最好的方法。 他不是迭加,也不是迭加
虽然在进程的地址空间中直接保留内存是最难使用的。 但是速度很快,是最灵活的。
2.5堆和堆栈中的存储内容
堆栈:函数调用时,第一个被堆栈的是主函数中后面的下一个指令()
语句)的地址,以及函数的各个参数。 在大多数C编译器中,参数是从右到左堆栈的
中选择所需的族。 以及函数中的局部变量。 请注意,静态变量不会进入堆栈。
这次函数调用结束后,局部变量先离开堆栈,然后出现参数,
最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。
2.6存取效率的比较
char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在运行时刻赋值的;
而bbbbbbbbbbb是在编译时就确定的;
但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。
比如:
#include
void main()
{
char a = 1;
char c[] = "1234567890";
char *p ="1234567890";
a = c[1];
a = p[1];
return;
}
对应的汇编代码
10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到
edx中,再根据edx读取字符,显然慢了。
2.7小结:
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就
走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自
由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由
度大。