C++ 动态内存

C++ 动态内存

一、程序内存分区概述

C++ 程序运行时内存主要分为:栈、堆、全局/静态区、常量区、代码区

日常开发中动态内存管理核心围绕**栈(Stack)堆(Heap)**展开。


二、栈(Stack)详细说明

  1. 管理方式

    由操作系统自动分配、自动回收,无需程序员手动干预。

  2. 存储内容

    函数局部变量、函数形参、临时变量、局部实例化对象。

  3. 生命周期

    绑定函数作用域,函数执行结束、作用域销毁时,栈内存立刻自动释放。

  4. 空间特性

  • 空间容量小、上限固定(系统默认数MB);
  • 内存地址连续,地址由高向低增长;
  • 空间不足会触发栈溢出(Stack Overflow)
  1. 访问效率

    内存连续、CPU寻址高效,读写速度快。

  2. 线程属性

    每个线程拥有独立栈空间,线程私有,不存在多线程竞争问题。


三、堆(Heap)详细说明

  1. 管理方式

    由程序员手动控制,通过 new / new[] 申请,delete / delete[] 手动释放。

  2. 存储内容

    动态变量、动态数组、大型对象、需要跨作用域长期使用的数据。

  3. 生命周期

    不受函数作用域限制,内存分配后会一直常驻,直到手动释放或程序进程结束;

    未手动释放会造成内存泄漏

  4. 空间特性

  • 空间极大,受系统虚拟内存限制,可灵活分配大容量内存;
  • 内存地址不连续,频繁分配释放易产生内存碎片
  • 分配失败返回空指针或抛出异常,无溢出风险。
  1. 访问效率

    分配与释放开销大,碎片化内存导致访问效率低于栈。

  2. 线程属性

    全局共享内存,多线程同时操作堆空间需要加锁保证线程安全。


四、堆与栈核心区别对照表

对比维度 栈(Stack) 堆(Heap)
内存管理者 系统自动管理 程序员手动管理
分配方式 自动分配 new 动态手动分配
释放方式 作用域结束自动释放 必须手动 delete 释放
空间大小 容量小、固定上限 空间大、支持动态扩容
内存布局 连续内存空间 非连续内存,易产生碎片
分配速度 快速高效 分配释放较慢
生命周期 随函数/作用域销毁 生命周期自定义,跨函数可用
典型用途 局部小变量、临时数据 大容量数据、动态数组、长生命周期对象
溢出问题 易发生栈溢出 无溢出,仅分配失败
地址增长方向 高地址 → 低地址 低地址 → 高地址
线程归属 线程私有 进程全局共享

五、C++ 动态内存:new 与 delete

5.1 核心作用

  • new:在堆区手动分配内存,自动调用类的构造函数
  • delete:释放堆区内存,自动调用类的析构函数

5.2 单个内存分配与释放

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

int main()
{
    // 堆上分配单个 double 内存
    double* pvalue = new double;
    *pvalue = 29494.99;

    cout << "堆内存变量值:" << *pvalue << endl;

    // 释放堆内存
    delete pvalue;
    pvalue = nullptr; // 释放后置空,避免野指针
    return 0;
}

5.3 内存分配失败判断

堆内存不足时 new 会分配失败,增加空指针判断保证程序健壮性:

cpp 复制代码
double* p = nullptr;
if (!(p = new double))
{
    cout << "内存不足,分配失败!" << endl;
    exit(1);
}

六、动态数组内存分配

6.1 一维动态数组

cpp 复制代码
// 分配堆数组
int* arr = new int[10];

// 使用数组
for(int i = 0; i < 10; ++i)
    arr[i] = i;

// 数组释放必须使用 delete[]
delete[] arr;
arr = nullptr;

6.2 二维动态数组

cpp 复制代码
// 二维数组开辟
int row = 3, col = 4;
int** mat = new int*[row];
for(int i = 0; i < row; ++i)
{
    mat[i] = new int[col];
}

// 二维数组释放
for(int i = 0; i < row; ++i)
{
    delete[] mat[i];
}
delete[] mat;
mat = nullptr;

6.3 关键规则

  • new[] 开辟数组,必须配套 delete[] 释放;
  • 混用 new / delete[] 会导致内存泄漏、程序崩溃。

七、对象动态内存分配

使用 new / delete 操作类对象,会自动触发构造与析构:

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

class Box
{
public:
    Box()
    {
        cout << "调用构造函数" << endl;
    }
    ~Box()
    {
        cout << "调用析构函数" << endl;
    }
};

int main()
{
    // 堆上创建 4 个对象,调用 4 次构造
    Box* boxArr = new Box[4];

    // 释放数组对象,调用 4 次析构
    delete[] boxArr;
    boxArr = nullptr;
    return 0;
}

八、new/delete 与 malloc/free 对比

  1. malloc / free
  • C 语言标准库函数;
  • 仅负责原始内存的申请与释放
  • 不调用构造函数、析构函数,不适合 C++ 面向对象开发。
  1. new / delete
  • C++ 专属运算符;
  • 分配内存 + 自动调用构造函数;
  • 释放内存 + 自动调用析构函数;
  • 类型安全,支持重载,C++ 项目优先使用

九、动态内存使用规范与注意事项

  1. 配对原则:new 对应 deletenew[] 对应 delete[],禁止混用;
  2. 内存泄漏:堆内存必须手动释放,长期遗漏会导致程序内存占用持续上涨;
  3. 野指针规避:内存释放后,立即将指针赋值为 nullptr
  4. 禁止重复释放、悬空指针访问已释放内存;
  5. 场景选择:
    • 短期、局部、小数据 → 使用栈内存;
    • 大数据、动态长度、跨作用域 → 使用堆内存;
  6. 多线程开发中,共享堆资源需做好同步加锁。

十、代码示例:栈内存 vs 堆内存

cpp 复制代码
// 栈内存:自动分配自动释放
void stackDemo()
{
    int a = 10;         // 栈变量
    char buf[1024];     // 栈数组
    Box box;            // 栈对象
}
// 函数结束,所有栈变量自动销毁

// 堆内存:手动管理
void heapDemo()
{
    int* pNum = new int(100);
    Box* pBox = new Box;
    int* pArr = new int[20];

    // 手动释放
    delete pNum;
    delete pBox;
    delete[] pArr;
}
相关推荐
hi_ro_a2 小时前
C++ 哈希表封装 unordered_map /unordered_set
数据结构·c++·算法·哈希算法
m0_617881426 小时前
如何高效进行堆叠分类器的超参数调优:解决 GridSearchCV 卡顿问题
jvm·数据库·python
m0_588758486 小时前
如何高效批量删除SQL数据_使用脚本分段删除降低压力
jvm·数据库·python
abc123456sdggfd6 小时前
Layui表单验证失败时如何修改默认弹出的Tips气泡颜色
jvm·数据库·python
2301_800976937 小时前
数据库的基本操作后续
java·数据库·sql
SECS/GEM7 小时前
SECS/GEM如何实现越南现场自定义消息
java·服务器·数据库
橘颂TA7 小时前
【Linux】读写锁
大数据·linux·开发语言·c++·读写锁
霍田煜熙7 小时前
HuoTian的两赛vlog(游记)~(2026.04.26写)
c++·奥数·双赛·vlog
lv__pf7 小时前
集合框架1
java·开发语言