写程序的时候都会遇到哪些内存问题
| 内存问题类型 | 主要含义 | 潜在影响与常见场景 |
|---|---|---|
| 内存泄漏 (Memory Leak) | 分配的内存未能释放,不再使用的内存无法回收 。 | 应用程序内存逐渐耗尽,运行变慢,甚至异常终止 。长期运行的系统(如服务器、后台服务)影响更大。 |
| 内存溢出 (Out of Memory) | 程序申请内存时,系统没有足够的空间满足其请求 。 | 程序运行中断或崩溃。常见于处理大量数据、内存设置过小或内存泄漏积累后 。 |
| 内存越界 (Out-of-Bounds Access) | 访问了分配时规定的内存范围之外的空间(如数组越界)。 | 数据损坏:可能破坏其他变量或关键数据;程序崩溃:访问非法地址时触发;安全漏洞:可能被利用执行恶意代码 。 |
| 缓冲区溢出 (Buffer Overflow) | 向缓冲区(如数组)写入超过其容量的数据,覆盖了相邻内存 。 | 同内存越界类似,但常强调因写入过多数据导致溢出,是安全攻击的常见目标 。 |
| 悬空指针/野指针 (Dangling Pointer/Wild Pointer) | 指针指向的内存已被释放或未初始化 。 | 访问它们会导致未定义行为,如读取到垃圾数据或程序崩溃 。 |
| 访问未初始化内存 (Accessing Uninitialized Memory) | 读取了未赋初值的内存内容,值不确定 。 | 程序行为不可预测,结果可能错误 。 |
| 双重释放 (Double Free) | 对同一块动态内存释放了两次 。 | 可能破坏内存管理器的数据结构,导致程序崩溃或潜在的安全问题 。 |
| 内存碎片 (Memory Fragmentation) | 虽有足够的总空闲内存,但缺乏大的连续块来满足分配请求 。 | 可能导致内存分配失败(即使总内存足够),降低内存使用效率 。 |
-
内存泄漏 (Memory Leak):指的是程序未能释放不再使用的内存。就像水池有个小洞在不停漏水,可用内存逐渐减少。积累到一定程度就可能引发内存溢出。
- 常发性内存泄漏:发生内存泄漏的代码会被多次执行到,每次执行都导致一块内存泄漏 。
- 偶发性内存泄漏:发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生 。
- 一次性内存泄漏:发生内存泄漏的代码只会被执行一次,或者由于算法缺陷,导致总有且仅有一块内存发生泄漏 。
- 隐式内存泄漏:程序在运行过程中不停的分配内存,直到结束时才释放。对于需长期运行的程序(如服务器),这可能导致内存耗尽 。
我对于内存问题在写代码的应对方式
第一个肯定是良好的编程习惯
遵循RAII原则()、使用智能指针(想要做的就是对资源的及时回收防止内存泄漏)
注意不要栈溢出(比如说递归终止条件、有栈协程分配空间的时候)、容器或数组的越界、程序向系统索要内存问题。
编译阶段
(c/c++)
ASan: 内存错误
TSan: 线程竞争
UBSan: 未定义行为
LSan: 内存泄漏
| Sanitizer工具 | 检测的问题 |
|---|---|
| AddressSanitizer (ASan) | 内存越界、use-after-free |
| UndefinedBehaviorSanitizer (UBSan) | 整数溢出、除零、空指针 |
| ThreadSanitizer (TSan) | 多线程数据竞争 |
| LeakSanitizer (LSan) | 内存泄漏 |
使用问题
(仅在测试阶段使用)
TSan一般要单独使用(因为与UBSan不兼容)
LSan以及集成到ASan中了
g++ -o my_program my_program.cpp -g -fsanitize=<sanitizer_name>
LSan
g++ -o my_program my_program.cpp -g -fsanitize=leak
ASan
g++ -o my_program my_program.cpp -g -fsanitize=address
UndefinedBehaviorSanitizer (UBSan)
g++ -o my_program my_program.cpp -g -fsanitize=undefined
TSan
g++ -o my_program my_program.cpp -g -fsanitize=thread
也可以集成使用,通常是将ASan与UBSan集成
g++ -o my_program my_program.cpp -g -fsanitize=address,undefined
//
g++ -O1 -g -fno-omit-frame-pointer -fsanitize=address,undefined -o my_program my_program.cpp
# 注意:LeakSanitizer (leak) 不需要显式写出,因为它已包含在 address 中。
放到cmake中
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 创建可执行文件
add_executable(my_program my_program.cpp)
# 为特定目标设置编译和链接选项
target_compile_options(my_program PRIVATE
-O1
-g
-fno-omit-frame-pointer
-fsanitize=address,undefined
)
# Sanitizer 通常也需要链接相应的运行时库
target_link_libraries(my_program PRIVATE
-fsanitize=address,undefined
)
Valgrind
(c/c++ linux)
wait....