C++内存四区之代码区、全局区、栈区和堆区

C++内存四区

C++ 在程序执行时,将内存大致分为代码区,全局区,栈区和堆区四个区域。不同的区域存储不同的数据,赋予不同的生命周期,能够更灵活地进行编程。

  1. 代码区:存放函数体的二进制代码,由操作系统管理创建,代码区时共享的,对于频繁被执行的程序,只需要存有一份代码即可;
  2. 全局区:存放全局变量和静态变量以及常量,在程序结束后由操作系统释放;
  3. 栈区:由编译其自动分配释放,存放函数的参数值以及局部变量等;
  4. 堆区:一般由程序员通过 new 开辟空间,进行分配和释放,若程序员不释放,则程序结束时由操作系统回收

下面通过一个例子对全局区,栈区,堆区的数据声明周期进行说明:

// 全局变量属于全局区,由操作系统管理释放
int g_a = 1;
int g_b = 2;
int main(void)
{
 cout << "g_a 的地址为:\t"<< int(&g_a) << endl;
 cout << "g_b 的地址为:\t" << int(&g_b) << endl;
 // 创建普通的局部变量,属于栈区
 int a = 10;
 int b = 20;
 cout << "a 的地址为:\t" << int(&a) << endl;
 cout << "b 的地址为:\t" << int(&b) << endl;
 // 创建静态变量,属于全局区
 static int s_a = 40;
 static int s_b = 50;
 cout << "s_a 的地址为:\t" << int(&s_a) << endl;
 cout << "s_b 的地址为:\t" << int(&s_b) << endl;
 // 程序员自己创建变量,属于堆区
 int* d_a = new int(10);
 int* d_b = new int(20);
 cout << "d_a 的地址为:\t" << int(d_a) << endl;
 cout << "d_b 的地址为:\t" << int(d_b) << endl;
}

输出结果为:

g_a 的地址为:  5300224  g_b 的地址为:  5300228 
a 的地址为:    6421316  b 的地址为:    6421304
s_a 的地址为:  5300232  s_b 的地址为:  5300236
d_a 的地址为:  9547944  d_b 的地址为:  9547992

我们从中可以看到,g_a,g_b,s_a,s_b 都属于全局区,同理,a,b 都属于栈区,d_a,d_b 都属于堆区。由于栈区的数据在程序运行结束后会被编译器自动销毁,因此不要返回局部变量的地址,举例如下:

int* func()
{
 int a = 10; // 栈区数据,在程序执行完之后自动释放
 return &a; //虽然返回了a的地址,然而数据在func结束时已经被销毁
}

int main(void)
{
 int* a = func(); // 此时a表示在函数func在栈区开辟的地址,但是其中的数据已被销毁
 cout << "a 的地址为:\t" << int(a) << "a 存放的数据为:\t" << *a << endl;
 cout << "a 的地址为:\t" << int(a) << "a 存放的数据为:\t" << *a << endl;
}

输出结果为:

a 的地址为:    7601480a 存放的数据为: 10
a 的地址为:    7601480a 存放的数据为: 2084553696

由于编译器会对栈区的数据做一次保留,因此第一条的 cout 语句能够正常输出,然而第二次的输出才是内存地址 a 中的数据。

相反,堆区数据由程序员自己进行管理,在程序执行完之后并不会自动释放。当整个程序执行完毕之后会由操作系统释放。

int* func()
{
 int * a = new int(10); // 程序员使用new在堆区开辟空间,在程序执行完之后自动释放
 return a; //同样返回了a的地址,然而只要程序没有运行结束,除非程序员释放,否则会一直保留
}

int main(void)
{
 int* a = func(); // 此时a表示在函数func在堆区开辟的地址,编译器无法自动销毁
 cout << "a 的地址为:\t" << int(a) << "a 存放的数据为:\t" << *a << endl;
 cout << "a 的地址为:\t" << int(a) << "a 存放的数据为:\t" << *a << endl;
}

输出结果为:

a 的地址为:    23507016a 存放的数据为:        10
a 的地址为:    23507016a 存放的数据为:        10

附:内存四区的小结

1、栈区(stack):就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是函数的返回地址、参数、局部变量、返回值等,从高地址向低地址增长。在一个进程中,位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数的调用。其操作方式类似于数据结构中的栈。

2、堆区(heap): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,在程序运行过程中可以动态增加堆大小(移动break指针),从低地址向高地址增长。

堆:是操作系统所维护的一块特殊内存,它提供了动态分配的功能,当运行程序调用malloc()时就会从中分配,稍后调用free()可把内存交还。

自由存储区:自由存储是C++中通过new和delete动态分配和释放对象的抽象概念,通过new来申请的内存区域可称为自由存储区。基本上,所有的C++编译器默认使用堆来实现自由存储,也即是缺省的全局运算符new和delete也许会按照malloc和free的方式来被实现,这时藉由new运算符分配的对象,说它在堆上也对,说它在自由存储区上也正确。但程序员也可以通过重载操作符,改用其他内存来实现自由存储,例如全局变量做的对象池,这时自由存储区和堆区就有区别了。

3、数据区:主要包括静态全局区和静态区,如果要站在汇编角度细分的话还可以分为很多小的区。

全局区&静态区:全局变量和静态变量被分配到同一块内存中,在以前的 C 语言中,全局变量和静态变量又分为

    全局初始化区(DATA段) :存储程序中已初始化的全局变量和静态变量

    未初始化段(BSS段) :存储未初始化的全局变量和静态变量(局部+全局)。BSS段在DATA段的相邻的另一块区域。

              BBS段特点:在程序执行前BBS段自动清零,所以未初始化的全局变量和静态变量在程序执行前已经成为0。

  在 C++ 里面没有这个区分了,他们共同占用同一块内存区。

4、代码区:包括只读存储区和文本区,其中只读存储区存储字符串常量,就是常量区,文本区存储程序的机器代码。

那“内存四区”和“内存五区”有什么区别吗?

其实“内存四区”和“内存五区”指的东西都是完全一样的

内存五区为:栈区、堆区、全局区(静态区)、常亮区、代码区

内存四区为:栈区、堆区、数据区(全局区(静态区)、常亮区)、代码区

因此从上面可以看出,对于内存四区而言,其只是把全局区(静态区)和常亮区合并为一个数据区而已,其实内容都是完全一样的

总结

到此这篇关于C++内存四区之代码区、全局区、栈区和堆区的文章就介绍到这了,更多相关C++内存四区内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ 内存分区模型的使用(代码区、全局区、栈区、堆区、new)

    内存分区模型 1 代码区 2 全局区 // 全局变量.静态变量.常量 #include <iostream> using namespace std; // 全局变量.静态变量.常量 //全局变量 int g_a=10; int g_b=10; //const修饰的全局常量 const int c_g_a = 10; const int c_g_b = 10; int main() { //创建普通局部变量 int a = 10; int b = 10; cout << "

  • C++内存四区之代码区、全局区、栈区和堆区

    C++内存四区 C++ 在程序执行时,将内存大致分为代码区,全局区,栈区和堆区四个区域.不同的区域存储不同的数据,赋予不同的生命周期,能够更灵活地进行编程. 代码区:存放函数体的二进制代码,由操作系统管理创建,代码区时共享的,对于频繁被执行的程序,只需要存有一份代码即可: 全局区:存放全局变量和静态变量以及常量,在程序结束后由操作系统释放: 栈区:由编译其自动分配释放,存放函数的参数值以及局部变量等: 堆区:一般由程序员通过 new 开辟空间,进行分配和释放,若程序员不释放,则程序结束时由操作系

  • C++程序内存栈区与堆区模型案例分析

    目录 栈区: 栈区代码演示: 堆区: 堆区代码演示: new操作符: new操作符代码演示: 栈区: 由编译器自动分配释放,存放函数的参数值,局部变量等(由编译器管理其“生死”) 注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放 栈区代码演示: //内存四区-栈区 /* 栈区: 由编译器自动分配释放,存放函数的参数值,局部变量等(由编译器管理其"生死") 注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放 */ #include <iostream&

  • 详解C++内存的代码区,全局区,栈区和堆区

    目录 代码区: 全局区: 栈区 堆区 总结 今天无意中刷到了一篇关于c++内存的帖子,我发现那个人好像写的不太对,然后同时我自己也发现我对一块还不够了解,所以我干脆就自己去了解整理了一下:首先我们要大概知道四个区都是干什么的 代码区: 顾名思义,就是存放我们写的代码的地方,不过要注意的是存放的是二进制代码. 注意:我们写的所有的写的代码(包括注释.变量.语句等)都会放到代码区中. 全局区: 存放全局,静态变量以及常量. 注意: 1.全局区里有一个部分叫常量区,储存的是常量,如const修饰的全局

  • 浅析栈区和堆区内存分配的区别

    一直以来总是对这个问题的认识比较朦胧,我相信很多朋友也是这样的,总是听到内存一会在栈上分配,一会又在堆上分配,那么它们之间到底是怎么的区别呢?为了说明这个问题,我们先来看一下内存内部的组织情况. 从上图可知,程序占用的内存被分了以下几部分. 1.栈区(stack)由编译器自动分配释放 ,存放函数的参数值,局部变量的值等,内存的分配是连续的,类似于平时我们所说的栈,如果还不清楚,那么就把它想成数组,它的内存分配是连续分配的,即,所分配的内存是在一块连续的内存区域内.当我们声明变量时,那么编译器会自

  • C++深入浅出讲解内存四区与new关键字的使用

    目录 写在前面 内存四区 程序运行前 代码区 全局区 程序运行后 栈区 堆区 new关键字 new的基本语法 利用new开辟数组 写在前面 从本文开始我就要日常更新C++入门博文啦,从核心编程开始,之前的一些基础我就不再从零整理了,只有函数传参.结构体.指针.数组等稍微难理解的知识在之前的博文写的比较全面:因为竞争确实很大,其他人总结的也很好,要看更详细的基础就看本站的技能树,非常全面:我写博客的初衷一是可以记录自己的学习,加以巩固:二是给更多的人更容易的讲解来快速入门C++,C/C++永不过时

  • 详解C语言中的内存四区模型及结构体对内存的使用

    内存四区 1.代码区 代码区code,程序被操作系统加载到内存的时候,所有的可执行代码都加载到代码区,也叫代码段,这块内存是不可以在运行期间修改的. 2.静态区 所有的全局变量以及程序中的静态变量都存储到静态区. 3.栈区 栈stack是一种先进后出的内存结构,所有的自动变量,函数的形参都是由编译器自动放出栈中,当一个自动变量超出其作用域时,自动从栈中弹出.对于自动变量,什么时候入栈,什么时候出栈,是不需要程序控制的,由C语言编译器.实现栈不会很大,一般都是以K为单位的. 当栈空间以满,但还往栈

  • 全局静态存储区、堆区和栈区深入剖析

    在C++中,内存可分为系统数据区,自由存储区,文本区,const数据区,全局静态区,堆区和栈区.其中,系统数据区存放的是系统数据,我们是不能自由访问的,有时候windows系统会突然弹出一个消息框,内容是"内存不能为read"就是错误访问系统数据区的结果:自由存储区用来存放由C延伸而来的malloc()函数所分配的数据:文本区存放着我们的函数代码,我们调用函数时的底层行为就类似于先去操作一个指针,而这个指针就指向函数指令所在的地址,也就是在文本区中:const数据区,顾名思义,就是存放

  • javaScript实现可缩放的显示区效果代码

    本文实例讲述了javaScript实现可缩放的显示区效果代码.分享给大家供大家参考,具体如下: 这里演示可缩放的显示区,采用JS代码实现,鼠标按住区域的右下角,出现拖放箭头时,向下或向上拉,就可实现缩放操作,当区域较小时显示滚动条,平时也比较常见的效果,在此将JavaScript代码与大家分享. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-ksf-box-style-demo/ 具体代码如下: <HTML> <HEAD>

  • 简单说说JVM堆区的相关知识

    一.堆概述 一个jvm实例(进程)只存在一个堆内存,堆也是java内存管理的核心区域. java 堆区在jvm启动时即被创建,其空间大小也就被确定了 <java虚拟机规范>规定,堆可以处于物理上不连续的内存空间,但在逻辑上它应该被称为连续的 所有线程共享java堆,在这里和可以划分线程私有的缓冲区(tlab) 所有对象实例以及数组都应在运行时分配在堆中 方法结束后,堆中的对象不会马上被移除,仅仅在垃圾收集时候才会被移除 堆是gc执行垃圾回收的重点区域 1.1 堆内存细分 现代垃圾收集器大部分基

随机推荐