本文首发于 2015-05-04 14:50:16
一个由 C/C++ 编译的程序占用的内存分为以下几个部分:
它与数据结构中的堆是两回事,分配方式倒是类似于链表
。举例来说:
//main.cpp int a = 0; // 全局初始化区 char *p1; // 全局未初始化区 main() { int b; // 栈 char s[] = "abc"; // 栈 char *p2; // 栈 char *p3 = "123456"; // 123456\0 在常量区,p3在栈上。 static int c =0; // 全局(静态)初始化区 // 分配的 10 个和 20 个字节的区域就在堆区。 p1 = (char *)malloc(10); p2 = (char *)malloc(20); strcpy(p1, "123456"); // 123456\0 放在常量区,编译器可能会将它与p3所指向的"123456"优化成同一个位置 }
在函数体中定义的变量通常是在栈上,用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上。
在所有函数体外定义的是全局量,加了static修饰符后不管在哪里都存放在全局区(静态区),在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件使用,在函数体内定义的static表示只在该函数体内有效。
函数中的"123456"这样的字符串存放在常量区。
还有就是函数调用时会在栈上有一系列的保留现场及传递参数的操作。
堆: 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。它与数据结构中的堆是两回事,分配方式是类似于链表。可能用到的关键字如下:new、malloc、delete、free等等。
栈: 由编译器(Compiler)自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。当一个函数调用完返回后它会释放该函数中所有的栈空间。
栈(stack):
由系统自动分配。例如,声明在函数中一个局部变量 int b;
,系统自动在栈中为b开辟空间。
堆(heap):
需要程序员自己申请,并指明大小。
在C中 malloc 函数:
p1 = (char *)malloc(10);
在C++中用 new 运算符:
p2 = (char *)new char(10);
但注意 p1、p2 本身是在栈中的。
栈: 只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出
。
堆: 首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样代码中的 delete 语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
栈:
堆:
栈由系统自动分配,速度较快。但程序员是无法控制的。
堆是由malloc分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。
栈:
堆:
堆: char *s1 = "Hellow Word";
是在编译时就确定的;
栈:char s1[] = "Hellow Word";
是在运行时赋值的;用数组比用指针速度要快一些,因为指针在底层汇编中需要用edx寄存器
中转一下,而数组在栈上直接读取。
在栈上存取数据比通过指针在堆上存取数据快些。
欢迎关注我的微信公众号【MySQL数据库技术】。
标题 | 网址 |
---|---|
GitHub | https://dbkernel.github.io |
知乎 | https://www.zhihu.com/people/dbkernel/posts |
思否(SegmentFault) | https://segmentfault.com/u/dbkernel |
掘金 | https://juejin.im/user/5e9d3ed251882538083fed1f/posts |
开源中国(oschina) | https://my.oschina.net/dbkernel |
博客园(cnblogs) | https://www.cnblogs.com/dbkernel |