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. 程序的机器指令和函数体都存储在这个区域。
相关推荐
啊?啊?3 分钟前
14 C++ STL 容器实战:stack/list 模拟实现指南 + priority_queue 用法及避坑技巧
c++·
汉克老师10 分钟前
第十四届蓝桥杯青少组C++选拔赛[2023.2.12]第二部分编程题(4、最大空白区)
c++·算法·蓝桥杯·蓝桥杯c++·c++蓝桥杯
土了个豆子的1 小时前
03.缓存池
开发语言·前端·缓存·visualstudio·c#
羚羊角uou1 小时前
【Linux】匿名管道和进程池
linux·c++·算法
_extraordinary_1 小时前
Java 多线程(一)
java·开发语言
曙曙学编程1 小时前
stm32——独立看门狗,RTC
c语言·c++·stm32·单片机·嵌入式硬件
爱喝水的鱼丶1 小时前
SAP-ABAP: ABAP ASSIGN COMPONENT 语句详解:动态字段符号的利器作用用法示例详解
运维·开发语言·sap·abap·开发经验·动态字段符号
励志不掉头发的内向程序员1 小时前
C++进阶——多态
开发语言·c++·学习
雨中散步撒哈拉2 小时前
13、做中学 | 初一下期 Golang数组与切片
开发语言·后端·golang
0wioiw02 小时前
Go基础(③Cobra)
开发语言·后端·golang