C++程序的五大内存分区实例详解

目录
  • 1、栈内存区
    • 1.1、调用函数时通过栈来传递函数的参数值
    • 1.2、线程占用的栈内存是有上限的
  • 2、堆内存区
  • 3、全局/静态内存区
  • 4、文字常量区
  • 5、程序代码区

C++程序在运行时所占用的内存区域,一般可分为栈内存区、堆内存区、全局/静态内存区、文字常量内存区及程序代码区5大分区:

下面使用日常开发中的编程实例,详细介绍一下这5个分区,以便大家能更深刻的理解这5大内存分区。

1、栈内存区

栈内存区是我们用的最多的分区,只要有函数的地方都会使用到这个分区。栈分区是用来存放函数参数及函数局部变量值的内存区,是由编译器在编译时自动分配和释放的。

函数中的参数与函数中的局部变量占用的内存是代码执行到函数(进入函数)是分配的,在离开时函数时这些内存会自动被释放。下面从下面几个简单的实例来更进一步地认识栈内存。

1.1、调用函数时通过栈来传递函数的参数值

调用函数时时通过栈传递参数值的,即在调用函数之前要将函数的参数值依次压入到栈上,然后再去call被调用函数的。这点从汇编代码上可以清晰地看出来。比如下面一段简单的实现两数相加的代码:

// 被调用函数
int AddNum(int a, int b)
{
    int nSum = a + b;
    return nSum;
}

// 调用内调用函数的实例代码
int a = 7;
int b = 8;

int  nSum = AddNum(a, b);

可以在VS中查看上述C++代码对应的汇编代码。具体的做法是,将上述代码拷贝到VS中,启动VS调试,在鼠标右键单击显示的右键菜单中点击“转到反汇编”区查看C++代码对应的汇编代码:

从上述汇编代码可以看出,在调用AddNum函数之前,将要传入的参数a和参数b的值先压到栈上,然后再去call AddNum函数。作为被调函数的AddNum会从栈上读取传入的参数内容。

1.2、线程占用的栈内存是有上限的

线程占用的栈内存是有上限的,可以在创建线程时指定栈空间的大小。在Windows上,线程默认的栈空间是1MB。线程在某一时刻的函数调用堆栈中的所有函数占用的栈空间总和,就是当前时刻的线程占用的栈内存。

进入函数时会将该函数的栈空间累计到所在线程的栈空间占用内存数上(函数内部申请存放局部变量的栈空间),离开函数则会释放它占用的栈空间,就会将所在线程占用的栈内存数上减掉函该函数占用的空间。如果当前线程占用的栈空间大于线程的上限时(一般是在进入一个函数时触发),则会报出“stack overflow”的栈溢出异常:

程序会发生崩溃。

这里有一点需要说明一下,在某个函数中使用了switch...case语句,语句中包含了多个case分支,在这些分支中定义了一些局部变量,虽然这些局部变量的生命周期只位于case子句中,但是都是直接算在所在函数的栈空间上的,是刚执行进函数就分配好了,即便当前还没运行到对应的case子句中,即便这些case子句的局部变量的生命周期仅在case子句内!

2、堆内存区

堆内存也是我们最常用的内存区,因为每个线程的栈内存是有限的,我们一般将大部分数据要放置在堆内存中。

在C++中,malloc/new申请的内存都是从堆内存上分配的,用完后由free/delete区释放的。如果没有释放堆内存,则程序结束时由操作系统统一回收。

堆内存的管理比栈内存要复杂的多,如果是堆内存异常导致的崩溃,比栈内存异常(比如内存越界引起内存访问为例)导致的崩溃,要难查的多。

如果malloc/new来的内存在用完后没有释放,则会导致内存泄露,如果频繁执行的代码中有内存泄露则是致命的,因为随着程序的运行时间的加长,会产生越来越多的内存泄露,如果将所属进程虚拟内存耗尽,会产生“Out of memory”的异常:

程序直接闪退崩溃。

3、全局/静态内存区

全局变量和静态变量的内存就是在该区上分配的,全局变量和静态变量的生命周期也是一样的,都是在程序启动时分配内存的,在程序退出时释放内存的。

全局变量一般会使用extern关键字来声明,比如:

extern int m_nClientId;

而静态变量则是使用static关键字来声明:

static int nCount;

全局变量和静态变量都要求在定义的时候要初始化,注意此处讲的定义是和声明是相对应的概念。全局变量和静态变量的区别在于,全局变量的作用域更广,整个模块中都能使用。静态变量则因其定义的位置不同有不同的作用域。

可以在函数中定义静态变量,也可以在类中定义静态成员变量。函数中定义的静态变量只能在函数中被访问,类中定义的静态变量则可以在类外部使用“类名::静态成员变量名”去访问。

4、文字常量区

该分区是用来存放常量值,如常量字符串等,比如如下的字符串常量:(将字符串常量的地址赋值给指针p):

char* p = ”this is a test.”;

该字符串占用的内存地址就是文字常量区内存上的。

该部分内存中的内容是固定的常量,是不允许修改的,程序结束后由操作系统统一回收。这部分内容比较简单,没什么要讲的。

5、程序代码区

前面说的内存都是数据段的内存,是用来存放程序运行中的各种数据的;该部分的内存是代码段的内存,是用来存放程序二进制代码的。
      数据段的内存地址和代码段指令的地址,完全是两个概念,不能混为一谈。比如某个变量的内存地址是数据段的地址:

某条汇编指令的地址,则是代码段的地址:

是两个完全不搭嘎的地址,一定要区分开来。

到此这篇关于C++程序的五大内存分区实例详解的文章就介绍到这了,更多相关C++ 五大内存分区内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++中的内存分区介绍

    C++的内存划分为栈区.堆区.全局区/静态区.字符串常量和代码区. 这里去掉自由存储区,增加了代码区,理由会在下面讲到. 栈区:由系统进行内存的管理. 说明:主要存放函数的参数以及局部变量.栈区由系统进行内存管理,在函数完成执行,系统自行释放栈区内存,不需要用户管理.整个程序的栈区的大小可以在编译器中由用户自行设定,默认的栈区大小为3M. 全局/静态区:全局.静态数据存放在一起的,初始化的全局变量和静态变量是在一起的.未初始化的全局变量和静态变量是在相邻的空间中. 说明:全局变量和静态全局变量的

  • 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++ 面向对象程序设计--内存分区详解

    目录 一.分区的意义 二.代码区 1.定义 2.特点 三.全局区 1.定义 2.特点 3.相关代码 1)全局变量 2)静态变量 四.栈区--程序运行后 1.定义 2.相关代码 五.堆区--运行后 1.定义 2.相关代码和运行结果 总结 一.分区的意义 在讲分区前,先谈谈内存分区的意义,也就是为什么程序要进行分区? 笔者认为这是为了编程的灵活性,因为将内存分区后,不同区域的内存,相关的数据就有的不同的生命周期.以笔者之前的一篇算法复杂度的blog中提到栈帧空间为例,在此就是指栈区,而栈区多指非ma

  • C++程序的五大内存分区实例详解

    目录 1.栈内存区 1.1.调用函数时通过栈来传递函数的参数值 1.2.线程占用的栈内存是有上限的 2.堆内存区 3.全局/静态内存区 4.文字常量区 5.程序代码区 C++程序在运行时所占用的内存区域,一般可分为栈内存区.堆内存区.全局/静态内存区.文字常量内存区及程序代码区5大分区: 下面使用日常开发中的编程实例,详细介绍一下这5个分区,以便大家能更深刻的理解这5大内存分区. 1.栈内存区 栈内存区是我们用的最多的分区,只要有函数的地方都会使用到这个分区.栈分区是用来存放函数参数及函数局部变

  • C++程序的五大内存分区实力详解

    目录 1.栈内存区 1.1.调用函数时通过栈来传递函数的参数值 1.2.线程占用的栈内存是有上限的 2.堆内存区 3.全局/静态内存区 4.文字常量区 5.程序代码区 总结 C++程序在运行时所占用的内存区域,一般可分为栈内存区.堆内存区.全局/静态内存区.文字常量内存区及程序代码区5大分区: 下面使用日常开发中的编程实例,详细介绍一下这5个分区,以便大家能更深刻的理解这5大内存分区. 1.栈内存区 栈内存区是我们用的最多的分区,只要有函数的地方都会使用到这个分区.栈分区是用来存放函数参数及函数

  • C++中的内存对齐实例详解

    C++中的内存对齐实例详解 内存对齐 在我们的程序中,数据结构还有变量等等都需要占有内存,在很多系统中,它都要求内存分配的时候要对齐,这样做的好处就是可以提高访问内存的速度. 我们还是先来看一段简单的程序: 程序一 #include <iostream> using namespace std; struct X1 { int i;//4个字节 char c1;//1个字节 char c2;//1个字节 }; struct X2 { char c1;//1个字节 int i;//4个字节 ch

  • 微信小程序的日期选择器的实例详解

    微信小程序的日期选择器的实例详解 前言: 关于微信小程序中的日期选择器大家用过都会发现有个很大的问题,就是在2月的时候会有31天,没有进行对闰年的判断等各种情况.看了官方文档提供的源码后进行了一些修改,测试修复了上面所说的bug! 下面源码: <!---js---> const date = new Date();//获取系统日期 const years = [] const months = [] const days = [] const bigMonth = [1,3,5,7,8,10,

  • 微信小程序 上传头像的实例详解

    微信小程序 上传头像的实例详解 最近在做微信小程序上传头像和上传照片功能就随手写一下代码: 上传头像html: <view class="edit-list"> <text class="list-name list-first">头像</text> <view class="edit-righr-bar"> <image class="head-portrait" src

  • 微信小程序 sha1 实现密码加密实例详解

    微信小程序 sha1 实现密码加密实例详解 在utils中的util.js 文件中增加 函数 实现 字符串转换为16进制加密后的字符串 function encodeUTF8(s) { var i, r = [], c, x; for (i = 0; i < s.length; i++) if ((c = s.charCodeAt(i)) < 0x80) r.push(c); else if (c < 0x800) r.push(0xC0 + (c >> 6 & 0x

  • 微信小程序 获取二维码实例详解

     微信小程序 获取二维码实例详解 理论: 接口A: 适用于需要的码数量较少的业务场景 接口地址:(永久有效,数量有限,进入path对应的页面) https://api.weixin.qq.com/wxa/getwxacode?access_token=ACCESS_TOKEN path String 不能为空,最大长度 128 字节 width Int 430(默认) 二维码的宽度 auto_color .. line_color .. 接口B:适用于需要的码数量极多,或仅临时使用的业务场景(永

  • 微信小程序之GET请求的实例详解

    微信小程序之GET请求的实例详解 学习前端的人应该都会使用ajax的get请求数据,那么在微信小程序里怎样实现get请求呢?下面我就给大家演示一下简单的get请求. 先上代码: //index.js //获取应用实例 var app = getApp() Page({ data: { motto: 'Hello World', onLoad: function () { var that = this wx.request({ url: 'http://apis.baidu.com/heweat

  • 微信小程序之数据缓存的实例详解

    微信小程序之数据缓存的实例详解 前言: 在H5之前,缓存一般都是用cookie,但是cookie的存储空间太小.于是,H5增加了新的缓存机制,即localstorage 和 sessionstorage,具体的介绍就不在多说.在微信小程序中,数据缓存其实就和localstorage 的原理差不多,所以理解起来并不难.下面我们来一起实现一下. 效果图展示: 我们在index页面存入数字11,然后在跳转到新页面,在将缓存中的11取出渲染到当前页面.具体代码如下: index页面: <span sty

  • 微信小程序 wx:for的使用实例详解

    微信小程序 wx:for的使用实例详解 在小程序的开发过程中,经常会用到在前端页面循环打印一个数组或者对象的数据,这样的话就需要用wx:for来实现. 一般情况下,小程序的utils这个文件夹下,我们可以把本地的数据写进去,封装成.js文件,提供对外暴露的接口,然后读取本地数据,这些在上一篇博客中有详细介绍.我们最后说到写好的本地数据可以另一个页面读取: var fileData = require('../../utils/data.js') Page({ data: { showData:

随机推荐