c++内存分区模型

程序在运行的过程中是会被加载到内存中的,一个程序可能会执行可能会存在不同的功能块,所以不同区域存放的数据,赋予不同的生命周期, 给我们更大的灵活编程

C++的程序会在内存中分为四大块:

  • 代码区:存放函数体的二进制代码,由操作系统进行管理的
  • 全局区:存放全局变量和静态变量以及常量
  • 栈区:由编译器自动分配释放, 存放函数的参数值,局部变量等
  • 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收

代码区

程序编译后是一个二进制的文件,这个二进制的文件便会放在代码区中。

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

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


全局区

  • 全局变量和静态变量存放在此.
  • 全局区还包含了常量区, 字符串常量和其他常量也存放在此.
  • 该区域的数据在程序结束后由操作系统释放.
  • C++中在程序运行前分为全局区和代码区
  • 代码区特点是共享和只读
  • 全局区中存放全局变量、静态变量、常量
  • 常量区中存放 const修饰的全局常量 和 字符串常量,局部变量和局部常量是另外一个内存块的栈的。

大概了解下是怎么回事就行,可以定义不同的变量去观察它们所在的地址块是否连续在一起来判断。


栈区

局部变量,局部常量都会分配到栈区中。

在函数中,实参传递给形参的过程是先在栈区为形参开辟一块内存块,然后将实参的值写入形参所在的内存块。这就是为什么需要修改一个实参的数时需要传递指针或者引用(引用其实也是一个指针)。通过指针的地址再去改变相应的值。

一个函数执行完之后,都会把在这个函数中创建的形参(本质也是一个局部变量)或者局部变量进行退栈操作,也就是销毁。销毁后的值是没有意义的。所以不能在一个函数中返回一个形参的地址,这是相当危险的操作。
如下程序:

int* test() {
	int i = 10; //在函数中创建的局部变量
	return &i; // 返回i的地址
}

int main() {
	int* p = test();
	cout << *p << endl;
	cout << *p << endl;
	cout << *p << endl;
	return 0;
}

结果:

10
1515108752
1515108752

结果只有第一次正确,这是因为编译器暂时保留了一会,等到第二次去取值时就错了。


堆区

那么,上面的问题中,我们要怎么在函数中创建变量,并且还不会在函数运行结束后就被销毁呢?
解决方案其实也很优雅,就是另外开辟一个堆区,将用户自己创建的变量都放到这个区中,然后用户自行删除或者等到程序结束时自动销毁。
主要是用new来开辟的内存空间的。

int* test() {
	int* i = new int(10); // 在堆中开辟新的空间
	return i; // 返回i
}

int main() {
	int* p = test();
	cout << *p << endl;
	cout << *p << endl;
	cout << *p << endl;
	return 0;
}

结果:

10
10
10

总结:

堆区数据由程序员管理开辟和释放

堆区数据利用new关键字进行开辟内存


本文主要参考:黑马程序员匠心之作|C++教程从0到1入门编程


更多精彩内容请关注我微信公众号:
在这里插入图片描述

<think>我们正在讨论C++内存分区模型。根据引用内容,C++内存通常分为以下几个区域:1.栈(Stack):存储局部变量、函数参数、函数返回地址等。由系统自动管理,分配和释放遵循先进后出原则。2.堆(Heap):用于动态分配的内存(如new/delete)。由程序员手动管理,需要注意内存泄漏和溢出。3.全局/静态存储区(Global/StaticStorage):存储全局变量和静态变量。在程序启动时分配,结束时释放。4.常量存储区(ConstantStorage):存放常量(如字符串常量)。只读,不可修改。 5.代码区(CodeArea):存放程序的执行代码(机器指令),只读。 现在,我将按照用户要求,清晰解释每个分区,并确保使用正确的LaTeX格式。注意:用户要求生成相关问题,所以最后需要生成相关问题。</think>### C++ 内存分区模型详解 C++ 程序在内存中的布局分为五个核心区域,每个区域具有特定的功能和生命周期管理规则: #### 1. 栈区(Stack) - **功能**:存储局部变量、函数参数、函数返回地址及函数调用的临时数据 - **管理方式**:系统自动管理(先进后出原则) - **特点**: - 连续内存空间,分配/释放速度快 - 大小有限(Windows 默认约 1-2MB) - 生命周期与作用域绑定 - **示例**: ```cpp void func() { int localVar; // 栈区变量 char buffer[64]; // 栈区数组 } ``` #### 2. 堆区(Heap) - **功能**:存储动态分配的内存(通过 `new`/`malloc` 申请) - **管理方式**:程序员手动管理(需显式释放) - **特点**: - 不连续内存空间,分配灵活 - 空间上限可达系统虚拟内存上限(32位系统理论 4GB) - 分配速度较慢,可能产生内存碎片 - **示例**: ```cpp int* ptr = new int(10); // 堆区分配 // ...使用ptr... delete ptr; // 必须手动释放 ``` #### 3. 全局/静态存储区(Global/Static Storage) - **功能**:存储全局变量、静态变量(`.data` 段存已初始化,`.bss` 段存未初始化) - **管理方式**:程序启动时分配,结束时释放 - **特点**: - 生命周期与程序相同 - 默认初始化为零值(未显式初始化时) - **示例**: ```cpp int globalVar = 1; // .data 段(已初始化全局变量) static int s_uninit; // .bss 段(未初始化静态变量) ``` #### 4. 常量存储区(Constant Storage) - **功能**:存储字符串常量和其他常量数据 - **管理方式**:只读内存,编译时确定 - **特点**: - 数据不可修改(修改会导致段错误) - 相同常量可能共享内存 - **示例**: ```cpp const char* str = "Hello"; // "Hello"存储在常量区 // str[0]='h'; // 非法操作! ``` #### 5. 代码区(Code Area) - **功能**:存储可执行指令(编译后的机器码) - **管理方式**:只读内存,由操作系统加载 - **特点**: - 包含所有函数体的二进制代码 - 共享内存提高效率(多进程可共享相同代码段) #### 内存布局示意图 ``` +------------------+ | 栈区 | 高地址 | ↓↓↓ | +------------------+ | 堆区 | | ↑↑↑ | +------------------+ | 全局/静态存储区 | | (.data/.bss) | +------------------+ | 常量存储区 | +------------------+ | 代码区 | 低地址 +------------------+ ``` > 关键特性对比: > | 分区 | 管理方 | 生命周期 | 大小限制 | 访问速度 | > |--------------|----------|----------------|----------------|----------| > | 栈 | 系统 | 作用域结束 | 固定(~2MB) | 最快 | > | 堆 | 程序员 | 直到显式释放 | 系统虚拟内存 | 慢 | > | 全局/静态存储 | 编译器 | 整个程序运行期 | 编译时确定 | 快 | > | 常量存储 | 编译器 | 整个程序运行期 | 编译时确定 | 快 | > | 代码区 | 操作系统 | 程序加载期 | 可执行文件大小 | N/A | 栈和堆的空间增长方向相反(栈向低地址扩展,堆向高地址扩展),这种设计可最大化利用内存空间[^1][^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值