Appearance
C++ 内存管理专题
一句话总览
C++ 面试「内存管理」覆盖:进程内存布局、堆与栈、malloc/free 与 new/delete、内存对齐、内存泄漏定位、以及虚拟内存。必须能讲原理,而不只是区别表。
问题清单(含答案)
内存布局 / 分配
1. 进程虚拟地址空间如何分布?
答案
从低到高:代码段(.text)、只读数据(.rodata)、已初始化数据(.data)、未初始化(.bss)、堆(向上增长)、共享库/mmap 区、栈(向下增长)、内核空间。详见 layout.md。
2. C++ 的内存分区?
答案
代码区(函数指令)、全局/静态区(.data/.bss)、堆(new/malloc 动态分配)、栈(局部变量/函数调用)、常量区(.rodata)。
3. 堆和栈的区别?
答案
栈编译器自动管理、快、小(默认 8MB)、LIFO、连续;堆手动管理、慢、大、可碎片化、任意顺序。栈分配只移动栈指针,堆要走分配器。
4. new 在哪分配?失败怎么办?
答案
在堆上分配。失败默认抛 std::bad_alloc;new (std::nothrow) 返回 nullptr;也可设 new_handler 在失败时处理。
5. 栈上放不下用堆;栈大小限制多少?
答案
Linux 默认 8MB(ulimit -s 查看)。递归过深或大局部数组会栈溢出(stack overflow)。
malloc / new
6. malloc 和 new 的区别?
答案
malloc 只分配原始内存、返回 void*、需指定字节数、失败返 NULL、不调构造;new 分配 + 调构造函数、返回类型化指针、失败抛异常、operator new 可重载。详见 malloc-new.md。
7. delete 和 delete[] 的区别?
答案
delete 调一次析构;delete[] 调 N 次析构。所以 new[] 会额外存元素个数(通常前缀 8 字节)供 delete[] 读取——用错会 UB。
8. malloc 底层?
答案
小块走 brk(移动堆顶)、大块走 mmap;内部用 free list/bins 管理空闲块(glibc ptmalloc)。
9. malloc(1KB) vs malloc(1MB)?
答案
glibc 有 MMAP_THRESHOLD(默认约 128KB):小于走 brk 的堆、free 后留在进程里复用;大于走 mmap 单独映射,free 直接 munmap 还给系统,避免大块长期占用。
10. new 的实现分几步?
答案
① operator new 分配内存(可重载)② 调构造函数。placement new 在已有内存上构造(不分配);new_handler 在分配失败时被调用(可重试或抛异常)。
对齐 / 内存细节
11. 什么是内存对齐?为什么?
答案
变量地址是其大小(或 alignas 指定值)的整数倍。原因:CPU 按对齐地址一次访存更快,未对齐可能跨 cache line/两次访存、部分平台直接异常。
12. 计算 sizeof(Struct)?
答案
按最大成员对齐,成员按声明顺序排、中间补 padding 到各自对齐边界,末尾再补到整体对齐。经典手算题见 alignment.md。
泄漏 / 排查
13. 内存泄漏怎么检测/避免?
答案
检测:valgrind(memcheck 报泄漏+未初始化读)、ASan(编译插桩,退出时报)、mtrace。避免:RAII/智能指针、用容器、明确所有权。详见 leak.md。
14. 程序崩溃 → core dump 怎么定位?
答案
开启 core(ulimit -c unlimited),崩溃后用 gdb ./prog core 加载,bt 看调用栈。详见 debugging/crash-debug.md。
子文档
| 文件 | 内容 |
|---|---|
index.md | 本文件 |
layout.md | 进程/虚拟内存布局、堆栈对比 |
malloc-new.md | malloc/new/delete/free 区别与底层 |
alignment.md | 内存对齐与 sizeof 手算 |
leak.md | 泄漏检测与避免 |