C++ 内存分区 堆区

一、堆区是什么?

堆区是 C++ 程序运行时,由程序员手动申请、手动释放的一块动态内存区域 。它不属于任何函数,不属于任何局部作用域,生命周期完全由程序员自己控制

  • 栈:系统自动管
  • 堆:程序员自己管
  • 全局区:程序启动就有,结束才没
  • 堆:想用就 new,不用就 delete

二、堆区的核心特点

1. 内存分配方式:动态分配

程序运行过程中随时可以申请、随时可以释放,大小可以任意指定。

2. 内存不连续

堆是链表结构 管理空闲块,多次申请的内存地址不连续

3. 空间巨大

栈只有几 MB,堆可以用到 几 GB(受操作系统限制)。

4. 分配速度比栈慢

因为需要遍历空闲链表、分配、标记、防止碎片。

5. 生命周期由程序员控制

  • new → 分配
  • delete → 释放
  • 不释放 → 内存泄漏
  • 释放后再用 → 野指针、崩溃

6. 多线程共享

同一个进程内的所有线程,共享同一个堆空间


三、堆区用来存什么?

  1. 动态大小的数组(运行时才知道大小)
  2. 大对象(太大栈放不下)
  3. 需要跨函数、跨作用域使用的对象
  4. 容器底层(vector、string、map 全在堆上)

四、堆区的使用方式(C++ 标准)

1. 申请单个变量

cpp

运行

复制代码
int* p = new int(100);  // 堆上分配 int,值=100

2. 申请数组

cpp

运行

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

3. 释放内存

cpp

运行

复制代码
delete p;       // 释放单个变量
delete[] arr;   // 释放数组 必须加[]

4. 最规范写法

cpp

运行

复制代码
int* p = new int(20);
delete p;
p = nullptr;  // 释放后置空,避免野指针

五、堆区底层原理(非常重要)

1. 堆内存如何分配?

操作系统维护一个 空闲内存链表

  • new → 遍历链表找一块足够大的内存
  • 标记为已使用
  • 返回地址给程序

2. 堆内存增长方向

从低地址 → 高地址(和栈相反)

3. 堆内存不会自动释放

只有两种情况会释放:

  1. 程序员 delete
  2. 程序结束,OS 回收

六、堆区常见错误(90% 的人都踩过)

1. 内存泄漏(最常见)

cpp

运行

复制代码
void func() {
    int* p = new int(10);
} // 函数结束,p 销毁,但堆内存还在!泄漏了

2. 重复释放

cpp

运行

复制代码
int* p = new int;
delete p;
delete p; // 崩溃!重复释放堆内存

3. 释放后继续使用(野指针)

cpp

运行

复制代码
int* p = new int(10);
delete p;
*p = 20; // 严重错误!访问已释放的堆内存

4. new /delete 不匹配

cpp

运行

复制代码
int* arr = new int[10];
delete arr; // 错误!应该用 delete[]

5. 不初始化就使用

cpp

运行

复制代码
int* p = new int; // 未初始化,值是随机垃圾数

七、堆 vs 栈(最清晰对比)

表格

特点 栈区(stack) 堆区(heap)
谁管理 系统自动分配、自动释放 程序员手动 new/delete
速度 极快 较慢
空间 小(MB 级别) 大(GB 级别)
连续性 连续内存 不连续
生命周期 函数结束即销毁 手动控制
碎片 无碎片 容易产生内存碎片
方向 高地址 → 低地址 低地址 → 高地址
报错 栈溢出 内存不足、野指针、重复释放

八、堆区使用规范(企业级标准)

  1. 谁申请,谁释放
  2. new 必须配对 deletenew[] 配对 delete[]
  3. 释放后指针立刻置空 nullptr
  4. 不要返回栈指针,但可以返回堆指针
  5. 能用栈就不用堆,堆更耗性能
  6. 现代 C++ 尽量用 智能指针(unique_ptr/shared_ptr) 自动管理堆内存,避免泄漏
相关推荐
山峰哥9 小时前
数据库性能救星:Explain执行计划深度拆解
服务器·开发语言·数据库·sql·启发式算法
执笔画流年呀9 小时前
Linux搭建Java项目部署环境
java·linux·运维
程序员天天困9 小时前
Arthas ognl 表达式从入门到实战:掌握在线调试最强的表达式引擎
java·jvm·后端
IT_Octopus10 小时前
Spring Boot 中 ThreadLocal 请求上下文的完整生命周期
java·spring boot·spring
用户409666013175110 小时前
Lombok 你用对了吗?@Data 之外的 6 个隐藏神器
java·后端·代码规范
梅头脑10 小时前
交易跨10个库、日均千万订单——选错一次分布式事务方案,加班三个月重写
java·分布式
久久学姐11 小时前
基础转码学 AI:Java+Python 双语言入门,3 个月可落地实战项目
java·python·ai·转码·实战项目
花生了什么事o11 小时前
synchronized 与 ReentrantLock:Java 锁机制原理与实现对比
java·开发语言
aramae11 小时前
C++ IO流完全指南:从C标准库到C++流式编程
服务器·c语言·开发语言·c++·后端
ZHOU_WUYI11 小时前
4. light wam 模型loss计算过程
开发语言·人工智能·python