寫程序的時(shí)候都會(huì)遇到哪些內(nèi)存問(wèn)題
| 內(nèi)存問(wèn)題類型 | 主要含義 | 潛在影響與常見(jiàn)場(chǎng)景 |
|---|---|---|
| 內(nèi)存泄漏 (Memory Leak) | 分配的內(nèi)存未能釋放,不再使用的內(nèi)存無(wú)法回收 。 | 應(yīng)用程序內(nèi)存逐漸耗盡,運(yùn)行變慢,甚至異常終止 。長(zhǎng)期運(yùn)行的系統(tǒng)(如服務(wù)器、后臺(tái)服務(wù))影響更大。 |
| 內(nèi)存溢出 (Out of Memory) | 程序申請(qǐng)內(nèi)存時(shí),系統(tǒng)沒(méi)有足夠的空間滿足其請(qǐng)求 。 | 程序運(yùn)行中斷或崩潰。常見(jiàn)于處理大量數(shù)據(jù)、內(nèi)存設(shè)置過(guò)小或內(nèi)存泄漏積累后 。 |
| 內(nèi)存越界 (Out-of-Bounds Access) | 訪問(wèn)了分配時(shí)規(guī)定的內(nèi)存范圍之外的空間(如數(shù)組越界)。 | 數(shù)據(jù)損壞:可能破壞其他變量或關(guān)鍵數(shù)據(jù);程序崩潰:訪問(wèn)非法地址時(shí)觸發(fā);安全漏洞:可能被利用執(zhí)行惡意代碼 。 |
| 緩沖區(qū)溢出 (Buffer Overflow) | 向緩沖區(qū)(如數(shù)組)寫入超過(guò)其容量的數(shù)據(jù),覆蓋了相鄰內(nèi)存 。 | 同內(nèi)存越界類似,但常強(qiáng)調(diào)因?qū)懭脒^(guò)多數(shù)據(jù)導(dǎo)致溢出,是安全攻擊的常見(jiàn)目標(biāo) 。 |
| 懸空指針/野指針 (Dangling Pointer/Wild Pointer) | 指針指向的內(nèi)存已被釋放或未初始化 。 | 訪問(wèn)它們會(huì)導(dǎo)致未定義行為,如讀取到垃圾數(shù)據(jù)或程序崩潰 。 |
| 訪問(wèn)未初始化內(nèi)存 (Accessing Uninitialized Memory) | 讀取了未賦初值的內(nèi)存內(nèi)容,值不確定 。 | 程序行為不可預(yù)測(cè),結(jié)果可能錯(cuò)誤 。 |
| 雙重釋放 (Double Free) | 對(duì)同一塊動(dòng)態(tài)內(nèi)存釋放了兩次 。 | 可能破壞內(nèi)存管理器的數(shù)據(jù)結(jié)構(gòu),導(dǎo)致程序崩潰或潛在的安全問(wèn)題 。 |
| 內(nèi)存碎片 (Memory Fragmentation) | 雖有足夠的總空閑內(nèi)存,但缺乏大的連續(xù)塊來(lái)滿足分配請(qǐng)求 。 | 可能導(dǎo)致內(nèi)存分配失?。词箍們?nèi)存足夠),降低內(nèi)存使用效率 。 |
-
內(nèi)存泄漏 (Memory Leak):指的是程序未能釋放不再使用的內(nèi)存。就像水池有個(gè)小洞在不停漏水,可用內(nèi)存逐漸減少。積累到一定程度就可能引發(fā)內(nèi)存溢出。
- 常發(fā)性內(nèi)存泄漏:發(fā)生內(nèi)存泄漏的代碼會(huì)被多次執(zhí)行到,每次執(zhí)行都導(dǎo)致一塊內(nèi)存泄漏 。
- 偶發(fā)性內(nèi)存泄漏:發(fā)生內(nèi)存泄漏的代碼只有在某些特定環(huán)境或操作過(guò)程下才會(huì)發(fā)生 。
- 一次性內(nèi)存泄漏:發(fā)生內(nèi)存泄漏的代碼只會(huì)被執(zhí)行一次,或者由于算法缺陷,導(dǎo)致總有且僅有一塊內(nèi)存發(fā)生泄漏 。
- 隱式內(nèi)存泄漏:程序在運(yùn)行過(guò)程中不停的分配內(nèi)存,直到結(jié)束時(shí)才釋放。對(duì)于需長(zhǎng)期運(yùn)行的程序(如服務(wù)器),這可能導(dǎo)致內(nèi)存耗盡 。
我對(duì)于內(nèi)存問(wèn)題在寫代碼的應(yīng)對(duì)方式
第一個(gè)肯定是良好的編程習(xí)慣
遵循RAII原則()、使用智能指針(想要做的就是對(duì)資源的及時(shí)回收防止內(nèi)存泄漏)
注意不要棧溢出(比如說(shuō)遞歸終止條件、有棧協(xié)程分配空間的時(shí)候)、容器或數(shù)組的越界、程序向系統(tǒng)索要內(nèi)存問(wèn)題。
編譯階段
(c/c++)
ASan: 內(nèi)存錯(cuò)誤
TSan: 線程競(jìng)爭(zhēng)
UBSan: 未定義行為
LSan: 內(nèi)存泄漏
| Sanitizer工具 | 檢測(cè)的問(wèn)題 |
|---|---|
| AddressSanitizer (ASan) | 內(nèi)存越界、use-after-free |
| UndefinedBehaviorSanitizer (UBSan) | 整數(shù)溢出、除零、空指針 |
| ThreadSanitizer (TSan) | 多線程數(shù)據(jù)競(jìng)爭(zhēng) |
| LeakSanitizer (LSan) | 內(nèi)存泄漏 |
使用問(wèn)題
(僅在測(cè)試階段使用)
TSan一般要單獨(dú)使用(因?yàn)榕cUBSan不兼容)
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) 不需要顯式寫出,因?yàn)樗寻?address 中。
放到cmake中
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 創(chuàng)建可執(zhí)行文件
add_executable(my_program my_program.cpp)
# 為特定目標(biāo)設(shè)置編譯和鏈接選項(xiàng)
target_compile_options(my_program PRIVATE
-O1
-g
-fno-omit-frame-pointer
-fsanitize=address,undefined
)
# Sanitizer 通常也需要鏈接相應(yīng)的運(yùn)行時(shí)庫(kù)
target_link_libraries(my_program PRIVATE
-fsanitize=address,undefined
)
Valgrind
(c/c++ linux)
wait....