大家好,我是程序喵。
這篇文章分享一個(gè)面試中經(jīng)常被問(wèn)到的知識(shí)點(diǎn):堆內(nèi)存和棧內(nèi)存有什么區(qū)別?平時(shí)開(kāi)發(fā)應(yīng)該使用堆內(nèi)存還是棧內(nèi)存?
要回答這個(gè)問(wèn)題,我們首先需要知道什么是堆內(nèi)存,什么是棧內(nèi)存,它們的分配和回收有什么特點(diǎn)?
先介紹下棧內(nèi)存:
棧內(nèi)存是為線(xiàn)程留出的臨時(shí)空間,每個(gè)線(xiàn)程都有一個(gè)固定大小的棧空間,而且棧空間存儲(chǔ)的數(shù)據(jù)只能由當(dāng)前線(xiàn)程訪(fǎng)問(wèn),所以它是線(xiàn)程安全的。
??臻g的分配和回收是由系統(tǒng)來(lái)做的,我們不需要手動(dòng)控制。
當(dāng)一個(gè)函數(shù)調(diào)用時(shí),系統(tǒng)就會(huì)為該函數(shù)的調(diào)用分配??臻g,當(dāng)函數(shù)返回后,系統(tǒng)就會(huì)自動(dòng)回收這塊空間,同理,下次其它函數(shù)調(diào)用和返回,系統(tǒng)還是會(huì)自動(dòng)分配和回收空間。
那它是怎么分配和回收的呢?
可以看這兩個(gè)動(dòng)畫(huà)
棧空間的大小是固定的,它有一個(gè)水位線(xiàn),標(biāo)識(shí)??臻g的分配狀態(tài),水位線(xiàn)里面的表示已經(jīng)分配,然后這個(gè)水位線(xiàn)會(huì)根據(jù)函數(shù)調(diào)用和返回的情況自動(dòng)調(diào)整。
這里可以看到,??臻g的分配和回收非常簡(jiǎn)單,只需要調(diào)整水位線(xiàn)位置就可以了,沒(méi)有任何多余操作。
那堆內(nèi)存呢?
我們平時(shí)在C語(yǔ)言和C++中使用malloc和new分配的內(nèi)存就是堆內(nèi)存,堆內(nèi)存的一大特點(diǎn)就是大小不固定,可以動(dòng)態(tài)擴(kuò)容,空間由程序員動(dòng)態(tài)分配,更加靈活。
然而,既然有優(yōu)點(diǎn)也必然伴隨著缺點(diǎn)。
第一個(gè)缺點(diǎn)就是它容易產(chǎn)生內(nèi)存泄露,malloc出來(lái)的沒(méi)有free,new出來(lái)的如果沒(méi)有delete,都會(huì)產(chǎn)生內(nèi)存泄露,真正項(xiàng)目?jī)?nèi)存泄露產(chǎn)生的情況肯定比這個(gè)復(fù)雜的多。
第二個(gè)缺點(diǎn),容易產(chǎn)生內(nèi)存碎片,在分配和回收時(shí)需要對(duì)很多內(nèi)存碎片進(jìn)行整理,效率較低,具體可以看這個(gè)動(dòng)畫(huà)。
所以才會(huì)有很多自定義的內(nèi)存分配器,但它肯定還是沒(méi)有??臻g分配回收速度快。
第三個(gè)缺點(diǎn),線(xiàn)程不安全,它不像棧內(nèi)存是線(xiàn)程獨(dú)立的,堆內(nèi)存可以被一個(gè)進(jìn)程內(nèi)所有的線(xiàn)程訪(fǎng)問(wèn),多線(xiàn)程操作就容易產(chǎn)生問(wèn)題,很多奇奇怪怪的操作就是這么引起的。
那什么變量存儲(chǔ)在棧上,什么存儲(chǔ)在堆上呢?普通的A a,這種就是都存儲(chǔ)在棧上,當(dāng)使用new和malloc分配的空間會(huì)存儲(chǔ)在堆上,看這個(gè)圖:
new出來(lái)的實(shí)際空間是在堆上分配,然后在棧上開(kāi)辟一個(gè)指針大小的空間,這個(gè)空間有一個(gè)指針,指向堆上的那塊內(nèi)存,這樣給變量和堆內(nèi)存之間就關(guān)聯(lián)起來(lái)了。
那什么情況下使用棧內(nèi)存,什么情況下使用堆內(nèi)存呢?
我整理出來(lái)了一個(gè)表,貼在這里:
棧 | 堆 | |
---|---|---|
速度 | 快 | 慢 |
空間管理 | 高效,不會(huì)產(chǎn)生碎片 | 會(huì)產(chǎn)生內(nèi)存碎片 |
訪(fǎng)問(wèn)權(quán)限 | 只能局部變量 | 可以訪(fǎng)問(wèn)全局變量 |
空間大小限制 | 操作系統(tǒng)限制 | 沒(méi)有特定的限制 |
內(nèi)存分配 | 連續(xù) | 隨機(jī)分配 |
分配和釋放 | 編譯器指令自動(dòng)管理 | 程序員手動(dòng)管理 |
開(kāi)銷(xiāo) | 低 | 高 |
主要問(wèn)題 | 空間小 | 內(nèi)存碎片 |
靈活性 | 固定大小 | 可以resize |
這里可以根據(jù)實(shí)際需求來(lái)決定使用哪類(lèi)內(nèi)存。
當(dāng)然,其實(shí)也不用關(guān)注那么多,我一般就是大內(nèi)存使用堆,局部變量小內(nèi)存使用棧。
這里還涉及到很多其它知識(shí)點(diǎn),比如進(jìn)程的內(nèi)存空間布局是怎么樣的,棧空間會(huì)不會(huì)污染、堆內(nèi)存具體是怎么分配和回收的。
具體在我的公眾號(hào)里搜索吧,里面有很多相關(guān)文章。
最后是 提問(wèn)環(huán)節(jié) ,大家可以在評(píng)論區(qū)討論一下哈。
- 當(dāng)定義一個(gè)vector a(100); a在哪塊內(nèi)存?那100a的空間又在哪里?
- 當(dāng)定義一個(gè)array
a; a在哪塊內(nèi)存,那100個(gè)a的空間又在哪里?
參考鏈接
https://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap
https://www.guru99.com/stack-vs-heap.html
https://www.geeksforgeeks.org/stack-vs-heap-memory-allocation/
-
存儲(chǔ)
+關(guān)注
關(guān)注
13文章
4226瀏覽量
85578 -
線(xiàn)程
+關(guān)注
關(guān)注
0文章
503瀏覽量
19636 -
??臻g
+關(guān)注
關(guān)注
0文章
5瀏覽量
5430
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論