C++ 内存管理与编译原理 (面试复习2)

目录

[一、 内存布局 (Memory Layout)](#一、 内存布局 (Memory Layout))

[1. C++ 程序的内存分区](#1. C++ 程序的内存分区)

[2. 堆 (Heap) 和 栈 (Stack) 的区别](#2. 堆 (Heap) 和 栈 (Stack) 的区别)

[二、 内存分配 (Memory Allocation)](#二、 内存分配 (Memory Allocation))

[1. new / delete 和 malloc / free 的区别](#1. new / delete 和 malloc / free 的区别)

[2. delete 和 delete[] 的区别](#2. delete 和 delete[] 的区别)

[3. 什么是内存泄漏 (Memory Leak)?如何检测?](#3. 什么是内存泄漏 (Memory Leak)?如何检测?)

[4. 什么是内存对齐 (Memory Alignment)?为什么要对齐?](#4. 什么是内存对齐 (Memory Alignment)?为什么要对齐?)

[三、 编译链接 (Compilation & Linking)](#三、 编译链接 (Compilation & Linking))

[1. 从源码到可执行文件的四个步骤](#1. 从源码到可执行文件的四个步骤)

[2. 静态链接和动态链接的区别](#2. 静态链接和动态链接的区别)

后续建议


一、 内存布局 (Memory Layout)

C++ 程序在运行时的内存空间通常被划分为以下几个主要区域(从高地址到低地址通常为栈向堆方向):

1. C++ 程序的内存分区
  1. 栈区 (Stack)

    • 由编译器自动分配和释放。

    • 存放函数的参数值、局部变量、返回值地址等。

  2. 堆区 (Heap)

    • 由程序员手动分配(new/malloc)和释放(delete/free)。

    • 若程序员不释放,程序结束时可能由 OS 回收。

  3. 全局/静态区 (Global/Static)

    • .data:存放已初始化的全局变量和静态变量。

    • .bss:存放未初始化的全局变量和静态变量(程序启动前由内核清零)。

  4. 常量区 (Literal/Constant)

    • 通常对应 .rodata 段。

    • 存放常量字符串、const 修饰的全局变量。此区域只读,修改会导致非法访问(Segmentation Fault)。

  5. 代码区 (Code/Text)

    • 存放函数体的二进制机器指令。
2. 堆 (Heap) 和 栈 (Stack) 的区别

这是面试中最高频的考点之一,建议从以下四个维度对比:

特性 栈 (Stack) 堆 (Heap)
申请方式 系统自动分配 。例如声明 int a; 程序员手动申请 。例如 new int(10);
分配效率 极高。仅需移动栈指针(寄存器操作),且有专门的指令支持。 较低。C 库需遍历空闲链表寻找合适大小的内存块,可能涉及系统调用。
空间大小 较小。通常为几 MB(如 Linux 默认 8MB,Windows 默认 1MB)。 很大。受限于虚拟内存空间,32位系统理论可近 4GB(实际约 2-3GB)。
碎片问题 无碎片。严格遵循 LIFO(后进先出),内存是连续的。 容易产生碎片。频繁的分配释放会导致内存空间不连续。

二、 内存分配 (Memory Allocation)

1. new / deletemalloc / free 的区别
特性 new / delete malloc / free
本质 C++ 运算符 (Operator),可重载。 C 标准库函数
构造/析构 自动调用new 先分配内存再调用构造函数;delete 先调析构再释放内存。 不调用。仅负责分配和释放纯粹的内存字节。
类型安全 类型安全。返回具体类型指针,无需强转。 不安全 。返回 void*,需要强制类型转换。
大小计算 编译器自动计算类型大小。 需要手动传递字节数(如 sizeof(T))。
2. deletedelete[] 的区别
  • 区别

    • delete:用于释放单个对象。

    • delete[]:用于释放数组。它会根据数组前的"cookie"(记录数组大小的信息)知道要调用多少次析构函数。

  • 如果在数组上错用 delete (如 int* p = new int[10]; delete p;)

    • 对于内置类型 (int, char):通常不会出大问题,内存会被释放(因为 allocator 知道块的大小),但这是 Undefined Behavior (UB)。

    • 对于自定义类 (Class)只会调用第一个对象的析构函数 ,剩余 9 个对象的析构函数不会被调用。如果对象内部管理着资源(如打开的文件、动态申请的内存),将导致严重的资源泄漏

3. 什么是内存泄漏 (Memory Leak)?如何检测?
  • 定义:程序动态申请了堆内存,但使用完后没有释放,导致这部分内存既不能被程序再次使用,也不能被操作系统回收(直到进程结束)。

  • 检测手段

    • Linux : 使用 Valgrind (valgrind --leak-check=full ./app)。

    • Windows (VS) : 使用 CRT Debug Library (_CrtDumpMemoryLeaks()) 或 Visual Studio 自带的诊断工具。

    • 代码层面 : 使用智能指针 (std::unique_ptr, std::shared_ptr) 实现 RAII,从根源杜绝泄漏。

4. 什么是内存对齐 (Memory Alignment)?为什么要对齐?
  • 定义 :数据在内存中的起始地址必须是其类型大小(或特定数值)的整数倍。例如,4 字节的 int 通常存储在地址能被 4 整除的地方。

  • 原因

    1. 性能 (Performance):CPU 读取内存通常按块读取(如 4 或 8 字节)。如果数据未对齐(跨越了两个块),CPU 需要做两次内存访问并进行拼接,效率减半。

    2. 平台兼容性 (Portability):某些硬件架构(如某些 ARM 或 RISC 架构)如果访问未对齐的内存,会直接触发硬件异常(Bus Error / Crash)。


三、 编译链接 (Compilation & Linking)

1. 从源码到可执行文件的四个步骤
  1. 预处理 (Preprocessing) (g++ -E):

    • 处理 #include(展开头文件)、#define(宏替换)、#ifdef(条件编译)。

    • 删除注释。

    • 生成 .i 文件。

  2. 编译 (Compilation) (g++ -S):

    • 语法分析、词法分析、语义分析。

    • 代码优化。

    • 将 C++ 代码翻译成汇编代码

    • 生成 .s 文件。

  3. 汇编 (Assembly) (g++ -c):

    • 将汇编代码翻译成机器能识别的机器码 (Machine Code)

    • 生成 .o (Linux) 或 .obj (Windows) 目标文件。

  4. 链接 (Linking) (g++ -o):

    • 合并多个 .o 文件和库文件。

    • 符号解析:找到函数和变量的定义。

    • 地址重定位:确定所有符号的最终内存地址。

    • 生成可执行文件 (.exe / .out)。

2. 静态链接和动态链接的区别
特性 静态链接 (Static Linking) 动态链接 (Dynamic Linking)
文件类型 .a (Linux), .lib (Windows) .so (Linux), .dll (Windows)
链接时机 编译链接阶段,代码被复制进可执行文件。 程序运行阶段,代码仅被引用,不复制。
可执行文件大小 (包含所有依赖库代码)。 (仅包含引用信息)。
依赖性 。发布时不需带库文件,独立运行。 。运行环境必须有对应版本的动态库。
升级维护 。库更新需重新编译发布整个程序。 。只需替换动态库文件即可。

后续建议

这些是理论基础,为了加深印象,您可以尝试以下操作:

  • 写一个会导致内存泄漏的各种场景的小 Demo,然后用 Valgrind 跑一下,看它输出的报告是什么样的。

  • 查看汇编代码 :写一个简单的 main.cpp,使用 g++ -E main.cpp > main.ig++ -S main.cpp,亲自查看预处理和编译后的文件内容。

相关推荐
酷ku的森1 小时前
JVM垃圾回收机制
jvm
火山灿火山1 小时前
Qt信号和槽
开发语言·qt
赴前尘1 小时前
docker 配置ipv6地址
java·docker·容器
开开心心就好1 小时前
图片批量压缩工具:支持有损无损两种模式
java·游戏·pdf·excel·散列表·启发式算法·1024程序员节
Overt0p1 小时前
博客系统(2)
java
这样の我1 小时前
java 模拟chrome tls指纹
java·开发语言·chrome
w1wi1 小时前
【环境部署】MacOS安装Tomcat
java·macos·tomcat
m0_661279181 小时前
学习笔记-安装并启动 Jupyter Noteboo
开发语言·python
代码or搬砖1 小时前
常见的五个编译时异常和常见的五个编译时异常
开发语言·php