关注公众号,后台回复
找书+ C++Primer
获取C++相关电子书。
面向对象编程技术的核心和精髓。
内存分区模型
C++程序在执行时,将内存大方向划分为4个区域
-
代码区:存放函数体的二进制代码,由操作系统进行管理的 -
全局区:存放全局变量和静态变量以及常量 -
栈区:由编译器自动分配释放,存放函数的参数值,局部变量等 -
堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
内存四区意义: 不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程
什么是内存分区模型,分成了4个区,有什么用,分别说明每个区
内存分区模型是程序在运行时将内存划分为不同功能区域的机制,主要用于高效管理数据和代码的存储与访问。在大多数系统中,内存通常分为以下 4个核心区域,每个区域有明确的功能和特点:
1. 代码区(Text Segment)
-
功能:存放可执行代码(如函数、类方法)和只读常量(如字符串常量)。 -
特点: -
只读(防止程序意外修改指令)。 -
程序启动时由操作系统加载,生命周期与程序一致。 -
共享性:多个进程运行同一程序时,可共享代码区。 -
用途:确保指令安全、高效地执行。
2. 全局/静态区(Global/Static Segment)
-
功能:存储全局变量、静态变量(包括 static
修饰的局部变量)和常量数据(如全局const
变量)。 -
特点: -
数据在程序启动时分配,程序结束时释放。 -
未初始化的变量默认值为零(或空)。 -
分为 已初始化区(如 int a = 10;
)和 未初始化区(如int b;
)。 -
用途:长期保存程序运行期间需要全局访问的数据。
3. 栈区(Stack Segment)
-
功能:管理局部变量、函数参数和函数调用信息(如返回地址)。 -
特点: -
由编译器自动分配和释放(后进先出,LIFO)。 -
空间有限(通常几MB),分配速度快。 -
溢出风险:递归过深或局部变量过大时会导致栈溢出。 -
用途:高效支持函数调用和局部变量的生命周期管理。
4. 堆区(Heap Segment)
-
功能:动态分配内存(如 malloc
、new
申请的内存)。 -
特点: -
由程序员手动管理分配和释放(需用 free
或delete
,否则内存泄漏)。 -
空间大(受系统虚拟内存限制),但分配速度较慢。 -
灵活性:适合存储大小不确定或生命周期长的数据。 -
用途:支持程序运行时按需动态申请内存。
内存分区的作用
-
安全性:代码区只读防止指令被篡改,栈/堆隔离避免数据冲突。 -
效率:栈区快速分配释放,堆区灵活管理大内存。 -
资源管理:自动管理栈内存,减少程序员负担;堆区提供动态扩展能力。 -
共享性:代码区可被多进程共享,节省内存。
示例对比
|
|
|
|
|
---|---|---|---|---|
代码区 |
|
|
|
|
全局/静态区 |
|
|
|
|
栈区 |
|
|
|
|
堆区 |
|
|
|
|
常见问题
-
栈溢出:递归过深或定义超大局部数组(如 int arr[1000000]
)。 -
内存泄漏:堆区分配后未释放(如 malloc
后忘记free
)。 -
野指针:访问已释放的堆内存(需及时置空指针)。
理解内存分区模型有助于优化程序性能和排查内存相关错误(如崩溃、泄漏)。
New 和 Delete
以下是 new
和 delete
的经典用法代码示例,附带注释说明其操作逻辑及注意事项:
1. 基础用法:单个对象分配与释放
// 分配一个整型内存int* p = newint; // 在堆上分配一个未初始化的 int 空间*p = 42; // 写入数据delete p; // 释放内存,p 变为悬空指针(建议后续置空:p = nullptr;)// 分配并初始化对象classMyClass {public: MyClass(int val) : data(val) {}private:int data;};MyClass* obj = new MyClass(100); // 调用构造函数分配并初始化delete obj; // 调用析构函数并释放内存
2. 数组分配与释放
// 分配整型数组int* arr = newint[5]; // 分配 5 个 int 的连续空间for (int i = 0; i < 5; i++) { arr[i] = i * 10;}delete[] arr; // 必须用 delete[] 释放数组// 分配对象数组MyClass* objs = new MyClass[3]{10, 20, 30}; // 每个元素调用构造函数delete[] objs; // 对每个元素调用析构函数
3. 内存管理注意事项
// 错误示例 1: 内存泄漏(分配后未释放)voidleakMemory(){int* leak = newint(5);// 忘记 delete leak;}// 错误示例 2: 重复释放(导致崩溃)int* p = newint;delete p;delete p; // 未定义行为(p 指向无效内存)// 正确做法: 释放后置空指针int* p = newint(10);delete p;p = nullptr; // 防止误用悬空指针
4. 对比 new
/delete
与 malloc
/free
// malloc 不调用构造函数,free 不调用析构函数MyClass* m1 = (MyClass*)malloc(sizeof(MyClass)); // 对象未初始化free(m1);MyClass* m2 = new MyClass(50); // 调用构造函数delete m2; // 调用析构函数
5. 动态对象的封装管理(RAII推荐)
#include<memory>// 使用智能指针替代裸 new/delete(C++11+)std::unique_ptr<MyClass> smartPtr = std::make_unique<MyClass>(200);// 无需手动 delete,智能指针自动释放内存
关键规则总结
-
配对使用: new
对应delete
,new[]
对应delete[]
,不可混用。 -
初始化优先:使用 new
时可以初始化(如new int(10)
)。 -
避免悬空指针: delete
后及时置空指针。 -
RAII 原则:推荐使用智能指针( unique_ptr
/shared_ptr
)替代手动管理。
通过正确使用 new
和 delete
,可以高效管理堆内存,但需时刻警惕 内存泄漏、悬空指针 和 重复释放 等问题。
🔔 想要获取更多网络安全与编程技术干货?
关注 泷羽Sec-静安 公众号,与你一起探索前沿技术,分享实用的学习资源与工具。我们专注于深入分析,拒绝浮躁,只做最实用的技术分享!💻
扫描下方二维码,马上加入我们,共同成长!🌟
👉 长按或扫描二维码关注公众号
或者直接回复文章中的关键词,获取更多技术资料与书单推荐!📚
原文始发于微信公众号(泷羽Sec-静安):10x程序内存模型
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论