詳解C++的靜態(tài)內(nèi)存分配與動態(tài)內(nèi)存分配
I - 內(nèi)存分配概述
1.1 - 定義概述
內(nèi)存分配 (Memory Allocation) 是指為計算機程序或服務(wù)分配物理內(nèi)存空間或虛擬內(nèi)存空間的一個過程。通常在程序執(zhí)行前或執(zhí)行時完成內(nèi)存分配。
1.2 - 分類概述
存在兩種類型的內(nèi)存分配:
- 編譯時內(nèi)存分配或靜態(tài)內(nèi)存分配 (Compile-time or Static Memory Allocation)
- 運行時內(nèi)存分配或動態(tài)內(nèi)存分配 (Run-time or Dynamic Memory Allocation)
靜態(tài)內(nèi)存分配:
靜態(tài)內(nèi)存分配是由編譯器為聲明的變量分配內(nèi)存。內(nèi)存的地址可以通過地址操作符找到,并且可以賦值給指針變量。該內(nèi)存是在編譯時分配的。
動態(tài)內(nèi)存分配 :
在程序執(zhí)行時 (execution) 或 運行時 (run-time) 進(jìn)行的內(nèi)存分配被稱為動態(tài)內(nèi)存分配。庫函數(shù)例如 calloc() 和 malloc() 或者操作符 new 均支持分配動態(tài)內(nèi)存。動態(tài)分配的內(nèi)存空間,通過這些函數(shù)或操作符的返回值分配,賦值給指針變量。
1.3 - 區(qū)別概述
序號 | 靜態(tài)內(nèi)存分配 | 動態(tài)內(nèi)存分配 |
---|---|---|
1 | 在靜態(tài)內(nèi)存分配中,變量被永久地分配內(nèi)存,直到程序執(zhí)行結(jié)束/函數(shù)調(diào)用結(jié)束 | 在動態(tài)內(nèi)存分配中,只有當(dāng)你的程序單元被激活時才會為變量分配內(nèi)存 |
2 | 靜態(tài)內(nèi)存分配在程序執(zhí)行前完成 | 動態(tài)內(nèi)存分配在程序執(zhí)行過程中完成 |
3 | 使用棧來管理靜態(tài)分配的內(nèi)存 | 使用堆來管理動態(tài)分配的內(nèi)存 |
4 | 較不高效 (less efficient) | 較高效 |
5 | 在靜態(tài)內(nèi)存分配中,不存在內(nèi)存的重用 | 在動態(tài)內(nèi)存分配中,存在內(nèi)存的重用,而且在不需要時可以內(nèi)存可以被釋放 |
6 | 在靜態(tài)內(nèi)存分配中,一旦內(nèi)存被分配,內(nèi)存大小就不能再改變 | 在動態(tài)內(nèi)存分配中,分配了內(nèi)存后,內(nèi)存的大小可以改變 |
7 | 在靜態(tài)內(nèi)存分配方案中,我們不能重新使用未使用的內(nèi)存 | 動態(tài)內(nèi)存分配中,允許重復(fù)使用內(nèi)存。用戶可以在需要時分配更多的內(nèi)存。同時,用戶也可以在需要時釋放內(nèi)存。 |
8 | 在這種內(nèi)存分配方案中,執(zhí)行速度比動態(tài)內(nèi)存分配要快 | 在這種內(nèi)存分配方案中,執(zhí)行速度要比靜態(tài)內(nèi)存分配慢 |
9 | 編譯時內(nèi)存分配 | 運行時內(nèi)存分配 |
10 | 靜態(tài)分配的內(nèi)存從程序開始保持到程序結(jié)束 | 動態(tài)分配的內(nèi)存可以在任意時刻釋放 |
11 | 靜態(tài)的內(nèi)存分配常常用于數(shù)組等 | 動態(tài)的內(nèi)存分配常常用于鏈表等數(shù)據(jù)結(jié)構(gòu) |
II - 靜態(tài)內(nèi)存分配
內(nèi)存必須被分配給我們所創(chuàng)建的變量,這樣實際的變量才能存在?,F(xiàn)在有一個問題,即我們認(rèn)為它是如何運行的,以及它實際上是如何運行的?
計算機如何創(chuàng)建一個變量?
當(dāng)我們思考如何創(chuàng)造某樣?xùn)|西時,我們會想到“從零開始”著手干,而當(dāng)計算機創(chuàng)建一個變量 ‘X’ 時,實際上情況并不是這樣;對于計算機而言,更像是一種分配,計算機只是從許多預(yù)先存在的內(nèi)存單元中分配一個內(nèi)存單元給 X。
那么什么是靜態(tài)內(nèi)存分配?當(dāng)我們聲明變量時,我們實際上是在準(zhǔn)備所有會被使用的變量,這樣編譯器就知道被使用的變量實際上是用戶想要的程序的重要部分,而不是到處漂浮的流氓符號。因此,當(dāng)我們聲明變量時,編譯器實際做的是將這些變量分配到它們的房間(一個內(nèi)存單元)?,F(xiàn)在,可以看出,這是在程序執(zhí)行前完成的,你不能在程序執(zhí)行時用這種方法分配變量。
示例
void func() { int a; } int main() { int b; int c[12]; //... }
上述代碼中所有的變量都是靜態(tài)分配的。
III - 動態(tài)內(nèi)存分配
那么,既然已經(jīng)存在一種方式來完成內(nèi)存分配的工作,為什么我們需要引入另一種分配方法?為什么我們需要在程序執(zhí)行過程中分配內(nèi)存?
因為,盡管不是很顯而易見,但不能在運行時分配內(nèi)存,就降低了靈活性,并與空間效率相妥協(xié)。特別是,在那些事先不知道輸入的情況下,我們會在存儲的低效使用和缺乏或過多的空間用來輸入數(shù)據(jù)方面受到影響(給定一個固定長度的數(shù)組或類似的數(shù)據(jù)結(jié)構(gòu)來存儲數(shù)據(jù))。
所以引入動態(tài)內(nèi)存分配: 在運行時,存儲/內(nèi)存/單元可以分配給變量的機制被稱為動態(tài)內(nèi)存分配(不要與 DMA 相混淆)。因此,我們可以知道在運行期間分配內(nèi)存,這使我們能夠使用我們想要的存儲,而不用擔(dān)心任何浪費或者不足。
為什么要使用動態(tài)分配的原因
- 當(dāng)我們事先不知道程序需要多少內(nèi)存的時;
- 當(dāng)我們希望數(shù)據(jù)結(jié)構(gòu)沒有固定的內(nèi)存空間上限時;
- 當(dāng)你想更有效地使用你的內(nèi)存空間時。例如: 如果你為一個一維數(shù)組分配的內(nèi)存空間是
array[20]
,而你最終只使用了 10 個內(nèi)存空間,那么剩下的 10 個內(nèi)存空間就被浪費了,這些浪費的內(nèi)存甚至不能被其他程序變量所使用; - 動態(tài)創(chuàng)建的列表的插入和刪除可以非常容易地通過操作地址來完成,而在靜態(tài)分配的內(nèi)存中,插入和刪除會導(dǎo)致更多的移動和內(nèi)存浪費;
- 當(dāng)你想在編程中使用結(jié)構(gòu)和鏈表的概念時,動態(tài)內(nèi)存分配是必須的
C++ 代碼
int main(int argc, char* argv[]) { // 動態(tài)內(nèi)存分配 int* ptr = new int; int* ptr1 = new int[10]; // 動態(tài)分配內(nèi)存的釋放 delete ptr; delete [] ptr1; }
C 代碼
ptr = calloc(m, n);
等價于
ptr = malloc(m * n); memset(ptr, 0, m * n);
IV - 小結(jié)
有兩種類型的可用內(nèi)存 – 棧 (stack) 和堆 (heap)。靜態(tài)內(nèi)存分配只能在棧上進(jìn)行,而動態(tài)內(nèi)存分配可以在棧和堆上進(jìn)行。在堆上進(jìn)行動態(tài)分配的一個例子是遞歸,在遞歸中,函數(shù)按照出現(xiàn)的順序被放入調(diào)用堆,并在到達(dá)基數(shù)時一個一個地彈出。
當(dāng)在堆上分配內(nèi)存時,我們需要手動刪除內(nèi)存,因為即使分配的內(nèi)存范圍結(jié)束(如棧的情況),內(nèi)存也不會被編譯器自己釋放(取消分配 deallocate)。
4.1 - 靜態(tài)分配的優(yōu)缺點
優(yōu)點
- 使用簡單
- 分配和取消分配都由編譯器完成
- 高效的執(zhí)行時間
- 它使用棧數(shù)據(jù)結(jié)構(gòu)
缺點
- 內(nèi)存浪費問題
- 必須知道確切的內(nèi)存需求
- 一旦初始化后,內(nèi)存的大小不能調(diào)整
4.2 - 動態(tài)分配的優(yōu)缺點
優(yōu)點
- 動態(tài)分配是在運行時進(jìn)行的
- 只要我們需要,我們就可以分配(創(chuàng)建)額外的存儲
- 只要我們使用結(jié)束了,內(nèi)存就可以被取消分配(free / delete)動態(tài)空間
- 因此,人們總是可以準(zhǔn)確地?fù)碛兴璧目臻g量–不多也不少。
- 如果需要,內(nèi)存大小可以重新分配
缺點
- 由于內(nèi)存是在運行時分配的,因此需要更多的時間。
- 當(dāng)完成后,內(nèi)存需要由用戶釋放。這一點很重要,因為它更有可能變成難以發(fā)現(xiàn)的 bug。
總上所述,靜態(tài)內(nèi)存是編譯器提前分配的東西。而動態(tài)內(nèi)存是在執(zhí)行過程中由程序控制的東西。程序可以要求更多的內(nèi)存,也可以刪除部分分配的內(nèi)存。
到此這篇關(guān)于詳解C++的靜態(tài)內(nèi)存分配與動態(tài)內(nèi)存分配的文章就介紹到這了,更多相關(guān)C++ 內(nèi)存分配內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于C++面向?qū)ο笤O(shè)計的訪問性問題詳解
這篇文章主要給大家介紹了關(guān)于C++面向?qū)ο笤O(shè)計的訪問性問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-09-09如何使用C語言實現(xiàn)細(xì)菌的繁殖與擴(kuò)散
這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)細(xì)菌的繁殖與擴(kuò)散,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11C++實現(xiàn)LeetCode(2.兩個數(shù)字相加)
這篇文章主要介紹了C++實現(xiàn)LeetCode(兩個數(shù)字相加),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C++判斷主機是否處于聯(lián)網(wǎng)狀態(tài)
這篇文章主要為大家詳細(xì)介紹了C++判斷主機是否處于聯(lián)網(wǎng)狀態(tài),具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06