C++:内存管理:C++内存管理详解
创始人
2024-02-07 09:02:38

C++语言内存管理是指:对系统的分配、创建、使用这一系列操作。在内存管理中,由于是操作系统内存,使用不当会造成很麻烦的后果。本文将从系统内存的分配、创建出发,并且结合例子来说明内存管理不当会造成的结果以及解决方案。

一:内存

在计算机中,每个应用程序之间的内存是相互独立的,通常情况下应用程序A并不能访问应用程序B,当然我们可以使用一种特殊技术,让他们可以互相访问,但这个不是本文的重点。比如在计算机中,一个视频播放程序与一个浏览器程序,他们的内存并不能访问,每个程序所拥有的内存是分区进行管理的。

在计算机系统中,运行程序A将会在内存中开启程序A的内存区域1,运行程序B将会在内存中开辟程序B的内存区域2,内存1和内存2之间逻辑分离。

 1.1 内存四个区

在程序A开辟的内存区域1会被分为几个区域,这就是内存四区,内存四区分为栈区、堆区、数据区和代码区。

栈区:指的是存储一些临时变量的区域,临时变量包括了局部变量、返回值、参数、返回地址等,当这些变量超出了当前作用域时将会自动弹出。该栈的最大存储是有大小的且固定的,超过该代销将会造成栈溢出。

堆区:是一个比较大的内存空间,主要用于对动态内存的分配,在程序开发中一般是开发人员进行分配和释放,若在程序结束时都还未释放,系统将自动进行回收。

数据区:主要存放全局变量、常量、静态变量,数据区又可以划分为:全局区和静态区,全局变量和静态变量将会存放到该区域。

代码区:比较简单,主要存储可执行代码,该区域的属性是只读的。

1.2 通过代码证实内存四区的底层结构

栈区

由于栈区和堆区的底层结构比较直观的表现,我们在此使用代码只演示这两个概念来查看代码观察栈区的内存地址分配情况。

// main.cpp
#include
int main() {int a = 0;int b = 0;int c = 0;printf("变量a的地址: %d", &a);printf("\n变量b的地址: %d", &b);printf("\n变量c的地址: %d", &c);// 打印结果}

 

 为什么它们之间的地址不是增加而是减少呢?那是因为栈区的一种数据存储结构为先进后出,如图:

                                                 

  1. 首先栈的顶部为地址的“最小”索引,随后往下依次增大,但是由于堆栈的特殊结果,我们将变量a先进行存储,那么它的一个索引地址将会是最大的,随后依次减少。(即 6422300)
  2. 第二次存储的变量时b,该值得地址索引比a小4个字节(因为int类型在32位系统中占4个字节),所以在a地址的基础上减少4个字节(即:6422296)
  3. 第三次存储变量c,该值得地址索引比b小4个字节(即:6422292)
  4. 第三次存储变量d,该值得地址索引比c小1个字节(即:6422291),因为char字符占一个字节
  5. 由于a、b、c、d这四个变量同属一一个栈内,所以他们地址的索引是连续性的,但是如果我们创建一个静态变量将会是怎样的了 ?

数据区

我们定义一个全局变量和 静态变量看看效果


#include
int e = 0;
int main() {static int f = 0;printf("\n var e address: %d", &e);printf("\nvar f address: %d", &f);}// 打印结果var e address: 8430692var f address: 8430696

从这个例子可以看出,数据区的地址不是栈结构,它是由低向高分配的,这里还是和栈区有点区别的。

以上例子其实也说明了栈区的特性,就是容量具有固定大小,超过最大容量将会造成栈溢出


#includeint main() {char char_arr[1024 * 1000000000];char_arr[0] = 'a';
}// 编译之后直接会报错

 1.3 :为了解决上面这个问题(开辟大容量内存)

堆并没有栈一样的结构,也没有栈一样的先进后出。我们需要人为的对内存进行分配使用。


#include
#includeint main() {//定义一个指针:指向一个大容量的内存地址char* p1 = (char*)malloc(1024 * 1000);// 把字符串"here is heap"赋值到指针 p1指向的空间中std::string s = "here is heap";strcpy_s(p1, 1024,s.c_str());//打印内存空间的地址printf("p1 storage address: %d", p1);printf("\np1 storage: %s", p1);
}//打印结果p1 storage address: 19443776
p1 storage: here is heap

多说一点

char *p=new char[10];
p="hello";
delete p[];//此步释放时将报错❌

这是因为:在C++中,字符串常量"hello"被保存在常量存储区,而p="hello"操作是改变了指针的指向,使得指针p指向了常量存储区的"hello",造成了初始在堆上开辟的内存泄露,而delete无法释放常量存储区的内存,导致出错。

二:malloc和free使用

在 C 语言(不是 C++)中,malloc 和 free 是系统提供的函数,成对使用,用于从堆中分配和释放内存。malloc 的全称是 memory allocation 译为“动态内存分配”。

2.1 malloc和free

在开辟堆空间时我们使用的函数为 malloc,malloc 在 C 语言中是用于申请内存空间,malloc 函数的原型如下:

void *malloc(size_t size);

 在 malloc 函数中,size 是表示需要申请的内存空间大小,申请成功将会返回该内存空间的地址;申请失败则会返回 NULL,并且申请成功也不会自动进行初始化。

细心的同学可能会发现,该函数的返回值说明为 void *,在这里 void * 并不指代某一种特定的类型,而是说明该类型不确定,通过接收的指针变量从而进行类型的转换。在分配内存时需要注意,即时在程序关闭时系统会自动回收该手动申请的内存 ,但也要进行手动的释放,保证内存能够在不需要时返回至堆空间,使内存能够合理的分配使用。

未完待续:看完这篇你还能不懂C语言/C++内存管理?

 把内存管理理解好,C语言真的不难学。今天带你“攻破”内存管理

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...