網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
地址空間
首先我們回味一下之前的老圖,這個(gè)圖由于是我手殘加 ppt 即時(shí)創(chuàng)作,又因?yàn)槭荂語(yǔ)言入門時(shí)講的,內(nèi)容非常粗糙磕磣。要仔細(xì)研究這張圖我們應(yīng)該將它翻轉(zhuǎn)90度會(huì)更加容易理解更貼近原理:
我們所熟知的,棧區(qū)數(shù)據(jù)存儲(chǔ)的地址是從高地址到低地址,堆區(qū)數(shù)據(jù)存儲(chǔ)的地址則是由低到高,而堆區(qū)下面可細(xì)分為未初始化和已初始化的全局?jǐn)?shù)據(jù)區(qū),字符常量區(qū)和代碼區(qū)。而細(xì)心的你可能注意到了我代碼區(qū)下面留了一撮空間代表下面還有,但這一撮屬于灰色地帶,目前看作為 “內(nèi)存” ,但本質(zhì)上不是內(nèi)存,涉及到計(jì)算機(jī)操作系統(tǒng)原理不贅述。
從內(nèi)存中0x000……0到堆區(qū)的地方其實(shí)基本上伴隨整個(gè)程序的運(yùn)行一直都存在,我們相對(duì)熟悉的就是棧區(qū)和堆區(qū),棧區(qū)的我們函數(shù)調(diào)用后臨時(shí)變量在棧幀中形成,隨著申請(qǐng)與釋放來(lái)進(jìn)行空間管理。
那伴隨整個(gè)程序的運(yùn)行一直都存在的這部分?jǐn)?shù)據(jù),像 static 這類函數(shù)修飾的變量,為什么又會(huì)被改變生命周期呢?其實(shí)在編譯的時(shí)候就被編譯進(jìn)了全局?jǐn)?shù)據(jù)區(qū)。
指針與內(nèi)存關(guān)系
void function(char *a) { return 1; }
我們?cè)趯懞瘮?shù)時(shí)如果內(nèi)容傳的是指針,如果有好的習(xí)慣一般會(huì)先去對(duì)指針做一下合法性判定,這個(gè)判定什么意思,比如我們傳了一個(gè)野指針,它會(huì)指向內(nèi)存中任何一個(gè)位置,我是沒(méi)有辦法確認(rèn)這個(gè)隨機(jī)位置有無(wú)訪問(wèn)權(quán)限,所以要做合法性判定。
但是指針如果有具體的指向,對(duì)應(yīng)的合法性我們是沒(méi)辦法驗(yàn)證的,包括野指針,是不是很疑惑,野指針不是隨機(jī)指向,說(shuō)白了就是亂指,那還沒(méi)辦法驗(yàn)證嗎?是的,沒(méi)辦法。很簡(jiǎn)單,確認(rèn)指針具體值的合法性,這不是咱作為用戶可以做到的,這屬于操作系統(tǒng)職責(zé)。
這種尷尬的情況我們所謂的合法性判定怎么搞呢?我們所謂的“合法”是落足于應(yīng)用層面。其實(shí)所有的指針在沒(méi)有被使用時(shí),我們都應(yīng)該設(shè)置成 NULL,這是一個(gè)規(guī)范問(wèn)題。
在函數(shù)內(nèi)部要驗(yàn)證指針合法性時(shí),本質(zhì)上就是在驗(yàn)證指針( !=NULL)??梢灾苯?if 判斷,還有就是很多書中用的一個(gè)檢查指針的宏——assert ,一般是在調(diào)試階段使用,assert(name)如果內(nèi)部條件不滿足非空,就會(huì)直接咔嚓掉,中道崩殂沒(méi)有后續(xù)。但是不好意思,assert只能檢驗(yàn)是否 NULL,不能檢驗(yàn)是否為野指針。
內(nèi)存分配與初始化細(xì)節(jié)
之前就想專門提一下幾個(gè)和內(nèi)存空間有關(guān)聯(lián)的函數(shù),現(xiàn)在就放在這里一起總結(jié)了吧。
我們?yōu)橹羔樂(lè)峙淞藘?nèi)存,但是內(nèi)存大小多少會(huì)影響實(shí)際結(jié)果,不夠就會(huì)造成越界。
char *p = "hello"; char *q = (char*)malloc(sizeof(char)*strlen(p)+1*sizeof(char)); strcpy(q,p);
p是字符串變量,長(zhǎng)度為 5 個(gè)字符,但實(shí)際內(nèi)存占用 6 個(gè)字符,不要忘了" \0 ",所以我們做 +1 處理,分配完了記得要初始化,初始化為非必須操作,但建議初始化,這是為了能讓咱編碼盤的明明白白。我們初始化變量時(shí)直接 0 或者 NULL,數(shù)組可以 = {0},也可以使用 memset 函數(shù):
memset(a,0,sizeof(a));
它的 3 個(gè)參數(shù)分別代表起始地址,初始化設(shè)置的值以及設(shè)置的內(nèi)存大小,單位為字節(jié)。
內(nèi)存泄漏
int main() { while(1) { int *p = malloc(1024); } }
這里不做測(cè)試了,這會(huì)讓電腦越來(lái)越卡,死循環(huán)加申請(qǐng)空間,程序級(jí)別的老賴,空間只借不還,以上代碼就生動(dòng)詮釋了何為內(nèi)存泄漏。
給個(gè)C語(yǔ)言之外的問(wèn)題:程序掛了,已經(jīng)退出了,那內(nèi)存泄露問(wèn)題還在嗎?我自己的想法是在的,因?yàn)閮?nèi)存已經(jīng)被申請(qǐng)了,退出程序只是終止了空間繼續(xù)申請(qǐng),不影響已產(chǎn)生的空間。但是我錯(cuò)了,其實(shí)在程序退出時(shí),操作系統(tǒng)會(huì)強(qiáng)制拿回這部分空間,內(nèi)存泄漏也就不在了。
所以諸位警惕windows的操作系統(tǒng)和殺毒軟件這類常駐進(jìn)程,幾乎從來(lái)不會(huì)退出,最怕的就是內(nèi)存泄漏,藍(lán)屏安排,卡頓安排;但后端的服務(wù)器也是如此,無(wú)時(shí)無(wú)刻提供服務(wù),一但內(nèi)存泄露就會(huì)嘿嘿。
Cookie
malloc 之后空間要給 free 掉,我們 free(p)目前只知道堆空間的起始地址,并不知道要釋放多少空間,如果 p 是 5 個(gè)字節(jié),那么 free 一定會(huì)釋放的比5個(gè)字節(jié)多,那么辯證思維,其實(shí)申請(qǐng)的空間就一定會(huì)比 5 個(gè)字節(jié)多。
編譯器是怎么做到正確釋放呢?其實(shí)實(shí)際 malloc 申請(qǐng)空間的時(shí)候,系統(tǒng)就會(huì)給的更多,多出來(lái)的部分,記錄的就是申請(qǐng)的詳細(xì)信息:空間大小,申請(qǐng)時(shí)間等等,free 會(huì)確認(rèn)信息然后精準(zhǔn) free掉。
這部分多申請(qǐng)的空間叫 cookie,內(nèi)存級(jí)的 cookie,就是用來(lái)保存這些信息的。再延伸就是C語(yǔ)言的邊界操作系統(tǒng)了,不贅述。
所以我們?cè)?malloc 時(shí)肯定是申請(qǐng)大空間會(huì)更好,因?yàn)?cookie 的比例會(huì)更小,想象一下利息相同時(shí)你會(huì)借多借少就能體會(huì)了。
原文鏈接:https://blog.csdn.net/qq_61500888/article/details/122170203
相關(guān)推薦
- 2022-12-24 C++中析構(gòu)函數(shù)為何是虛函數(shù)_C 語(yǔ)言
- 2022-12-28 Android?ViewPager2?+?Fragment?聯(lián)動(dòng)效果的實(shí)現(xiàn)思路_Android
- 2022-12-27 詳解Golang中interface接口的原理和使用技巧_Golang
- 2023-08-28 React綁定antd輸入框,點(diǎn)擊清空或者確定按鈕實(shí)現(xiàn)清空輸入框內(nèi)容
- 2023-06-18 C#中獲取文件大小問(wèn)題_C#教程
- 2022-10-24 六個(gè)Python3中使用最廣泛的內(nèi)置函數(shù)總結(jié)_python
- 2022-10-05 C++淺析數(shù)據(jù)在內(nèi)存中如何存儲(chǔ)_C 語(yǔ)言
- 2022-10-26 go并發(fā)編程sync.Cond使用場(chǎng)景及實(shí)現(xiàn)原理_Golang
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支