C++ 内存分区模型

目录

程序运行前

代码区

全局区

程序运行后

new

在堆区开辟数据

delete释放堆区数据

堆区开辟数组

内存分区模型

栈(Stack)

堆(Heap)

[全局/静态存储区(Global/Static Storage)](#全局/静态存储区(Global/Static Storage))

[常量存储区(Constant Storage)](#常量存储区(Constant Storage))

[代码区(Code Area)](#代码区(Code Area))


程序运行前

在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域

代码区

存放 CPU 执行的机器指令

代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可

代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令

全局区

全局变量和静态变量存放在此.

全局区还包含了常量区 , 字符串常量其他常量也存放在此.

该区域的数据在程序结束后由操作系统释放

  • C++中在程序运行前分为全局区和代码区
  • 代码区特点是共享和只读
  • 全局区中存放全局变量、静态变量、常量
  • 常量区中存放 const修饰的全局常量 和 字符串常量
cpp 复制代码
#include <iostream>
using namespace std;

//全局变量
int g_a = 10;
int g_b = 10;

//全局常量
const int c_g_a = 10;
const int c_g_b = 10;

int main() {

		//局部变量
		int a = 10;
		int b = 10;


		//静态变量
		static int s_a = 10;
		static int s_b = 10;

	return 0;
}

程序运行后

不要返回局部变量的地址,栈区开辟的数据由编译器自动释放

cpp 复制代码
#include <iostream>
using namespace std;

int * func(int a) // 形参也是放在栈区
{
	int a = 10;
	return &a; // 不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
}

int main() {

	int *p = func();

	cout << *p << endl; // 10 第一次可以打印这个数字,是因为编译器做了保留
	cout << *p << endl; // 随机值 第二次这个数据就不再保留了
	 
	return 0;
}

new

利用new关键字,可以将数据开辟到堆区

在堆区开辟数据

int *p = new int(10)

new int(10)表示在堆内存上动态分配了一个int类型的空间,并用值10初始化了该空间。
p指针变量,本质上也是局部变量,放在栈上,指针指向的是所开辟的堆内存区的数据的地址。

int *p = func()

p虽然是在func()函数中声明的局部变量,但它存储的是一个指向堆内存的地址。
当函数func()执行完毕后,p虽然在函数栈帧中被销毁,但指向堆内存的地址仍然存在。

cpp 复制代码
int * func() {
	/*
		利用new关键字,可以将数据开辟到堆区
	*/
	int *p = new int(10); // new当前返回的是int类型的指针,具体什么类型由开辟的数据类型决定
	return p; // 客观上返回的是堆区的地址
}

int *p = func()

/*
	p虽然是在func()函数中声明的局部变量,但它存储的是一个指向堆内存的地址。
	当函数func()执行完毕后,p虽然在函数栈帧中被销毁,但指向堆内存的地址仍然存在。
*/
cout << *p << endl; // 10

delete释放堆区数据

cpp 复制代码
    int * func() {
	    int *p = new int(10); 
	    return p; 
    }

	int *p = func();
	delete p; // 释放堆区数据
	cout << *p << endl; // error 内存已经释放,再次访问已经是非法操作,报错

堆区开辟数组

在堆区开辟数组------创建10个整形数据的数组

  • new int[10]动态分配一个包含10个int类型元素的数组时,内存管理系统会分配一块连续的内存空间来存储这个数组。
  • 指针arr存储的就是这块内存空间的起始地址,也就是数组的第一个元素的地址。
  • 类似于C语言中的数组名
cpp 复制代码
void test() {
	/*
		new int[10]动态分配一个包含10个int类型元素的数组时,内存管理系统会分配一块连续的内存空间来存储这个数组。
		指针arr存储的就是这块内存空间的起始地址,也就是数组的第一个元素的地址。
		类似于C语言中的数组名
	*/
	int *arr = new int[10]; // 10代表数组有10个元素,注意这里是中括号,不是小括号
	for (int i = 0; i < 10; i++)
	{
		arr[i] = i + 100; // 给这10个元素赋值 1000~109 (arr[i] == *(arr + i))
	}
	for (int i = 0; i < 10; i++)
	{
		cout << arr[i] << endl; // 100 ~ 109
	}

	//释放堆区的数组数据内存。数组需要加 []
	delete[] arr;
}


test();

内存分区模型

C++的内存分区模型描述了程序在运行时如何使用系统内存。了解内存分区模型对于理解程序的内存管理和运行效率非常重要!

在一般情况下,C++程序在内存中的布局可以分为以下几个主要区域:

栈(Stack)

  1. 栈是用于存储局部变量、函数参数、函数返回地址以及函数调用时所需的临时数据的区域。
  2. 栈的大小在程序运行时是可以动态变化的,通常由系统自动管理。
  3. 栈内存的分配和释放是由系统自动完成的,遵循"先进后出"的原则。

堆(Heap)

  1. 堆被用于存储动态分配的内存,例如使用newdelete关键字来分配和释放的内存。
  2. 堆的大小也是动态变化的,可以在程序运行时根据需要进行分配和释放。
  3. 程序员通常需要手动管理堆内存的分配和释放,因此在使用时需要注意内存泄漏和内存溢出的风险。

全局/静态存储区(Global/Static Storage)

  1. 全局变量、静态变量以及常量通常存储在这个区域。
  2. 这部分内存在程序启动时就被分配,并在程序结束时才被释放,它们的生命周期与整个程序的生命周期相同。

常量存储区(Constant Storage)

  1. 存放常量数据,如字符串常量等。
  2. 这部分内存通常被固定分配,并且存储的数据在程序运行期间不会改变。

代码区(Code Area)

  1. 存放程序的执行代码,通常是只读的。
  2. 程序的机器指令和函数体都存储在这个区域。
相关推荐
@东辰1 分钟前
【golang-技巧】-自定义k8s-operator-by kubebuilder
开发语言·golang·kubernetes
乐悠小码8 分钟前
数据结构------队列(Java语言描述)
java·开发语言·数据结构·链表·队列
史努比.9 分钟前
Pod控制器
java·开发语言
敲敲敲-敲代码18 分钟前
游戏设计:推箱子【easyx图形界面/c语言】
c语言·开发语言·游戏
ROC_bird..27 分钟前
STL - vector的使用和模拟实现
开发语言·c++
机器视觉知识推荐、就业指导27 分钟前
C++中的栈(Stack)和堆(Heap)
c++
MavenTalk33 分钟前
Move开发语言在区块链的开发与应用
开发语言·python·rust·区块链·solidity·move
XiaoLeisj1 小时前
【JavaEE初阶 — 多线程】生产消费模型 & 阻塞队列
java·开发语言·java-ee
2401_840192271 小时前
python基础大杂烩
linux·开发语言·python
@东辰1 小时前
【golang-技巧】- 定时任务 - cron
开发语言·golang·cron