C 语言内存分配
1
昨天有一個群里的同學問我,他問我的問題是?c?語言函數是存在哪里的?是如何執行的?我下意識的覺得這位同學應該是個初學者,所以今天就寫下一些基礎方面的內容,「C語言的內存布局」。
程序代碼可以看做是一個人,是人就需要有房子住,操作系統就是政府,政府有義務給找個位置給你住,如果你是高級人才,他就給你個?vip?,給你分個大房子,但是如果你對社會沒有幫助(??手上沒錢),那你可能就需要住天橋下。
我們剛開始學習單片機的時候,還沒有進程,線程,操作系統的概念,程序直接下載到?rom?里面,等你有了操作系統概念,反過來看看,會覺得以前自己寫的代碼都是單線程的。
2
C?語言內存分配的框圖如下,一個正常的執行代碼,?操作系統需要給他分配一段內存區域,這一大塊內存區域還要分為幾個小區域。
1.文本段(Text segment)
2.初始化數據段(Initialized data segment)
3.未初始化數據段(Uninitialized data segment)
4.堆棧(Stack)
5.堆 (Heap)
3
1.文本段:
文本段,也稱為代碼段,是目標文件或內存中包含可執行指令的程序的一部分。
作為存儲區域,文本段可以放置在堆或堆棧下方,以防止堆和堆棧溢出覆蓋它。
通常,文本段是可共享的,因此對于頻繁執行的程序(例如文本編輯器,C?編譯器,shell?等),只需要一個副本就可以在內存中。此外,文本段通常是只讀的,以防止程序意外修改其指令。
文本段可以看做?這段代碼?的?大腦,需要怎么執行,做什么,都把數據保存在這個位置了。
2.初始化數據段:
初始化數據段,通常簡稱為數據段。數據段是程序的虛擬地址空間的一部分,其包含由程序員初始化的全局變量和靜態變量。
請注意,數據段不是只讀的,因為變量的值可以在運行時更改。
該段可以進一步分類為初始化的只讀區域和初始化的讀寫區域。
例如,C 中的 char s [] =“hello world”定義的全局字符串,和 int debug = 1 之類的 C語句 將存儲在初始化的讀寫區域中。像?const?char?*?string?=“hello?world”這樣的全局?C語句?會把?字符串文字“hello?world”存儲在初始化的只讀區域中,而字符指針變量字符串存儲在初始化的讀寫區域中。
例如:static?int?i?=?10?將存儲在數據段中,global?int?i?=?10?也將存儲在數據段中
3.未初始化的數據段:
未初始化的數據段,通常稱為“bss”段,以古代匯編運算符命名,代表“由符號啟動的塊”。此段中的數據在程序啟動之前由內核初始化為算術?0?執行
未初始化的數據從數據段的末尾開始,包含初始化為零或在源代碼中沒有顯式初始化的所有全局變量和靜態變量。
例如,變量聲明為static?int?i;?將包含在BSS部分中。
例如,一個聲明為int?j的全局變量;?將包含在BSS部分中。
4.堆棧:
我們很多時候說的堆棧,實際上就是棧(?stack?)跟堆(?heap?)是沒有關系的。我們學習上經常說的?壓棧,說的就是壓堆棧,因為堆棧有?「先進后出的原則」,所以我們操作的是棧尾。
堆棧區域傳統上與堆區域相鄰并向相反方向增長;?當堆棧指針遇到堆指針時,可用內存耗盡(因為理論上這個兩個家伙是不可能?相遇的)?。(使用現代大地址空間和虛擬內存技術,它們幾乎可以放置在任何地方,但它們通常仍會朝著相反的方向發展。)
堆棧區域包含程序堆棧,LIFO結構,通常位于存儲器的較高部分。在標準的PC?x86計算機體系結構上,它向零地址發展;?在其他一些架構上,它朝著相反的方向發展。“堆棧指針”寄存器跟蹤堆棧的頂部;?每次將值“推”到堆棧上時都會調整它。
5.堆:
堆是通常發生動態內存分配的段。
堆區域從BSS?段的末尾開始,并從那里增長到更大的地址。堆區域由?malloc,realloc?和?free?管理,可以使用?brk?和?sbrk?系統調用來調整其大小;它們也可以使用mmap實現,將不連續的虛擬內存區域保留到進程的“虛擬地址空間”中。堆區域由進程中的所有共享庫和動態加載的模塊共享。
4
實用?size?命令可以分析生成的可執行程序每個段的大小,單位是(bytes?字節)。我們可以用這個命令驗證上面的論證。
代碼實例
int?main()
{
????return?0;
}
Linux@dev:~/cStudy$?gcc?memory-test.c?-o?memory-test?&&?size?memory-test
???text????data?????bss?????dec?????hex?filename
???1099?????544???????8????1651?????673?memory-test
Linux@dev:~/cStudy$?
現在代碼里面什么都沒有,可以看到每個段內容的大小。
#include<stdio.h>int?g;
int?main()
{
????static?int?i;
????return?0;
}
--------------------------------------------------
Linux@dev:~/cStudy$?gcc?memory-test.c?-o?memory-test?&&?size?memory-test
???text????data?????bss?????dec?????hex?filename
???1099?????544??????16????1659?????67b?memory-test
Linux@dev:~/cStudy$?
我們聲明了一個未初始化的全局變量和一個未初始化的靜態變量后,bss?段發生了變化。
再修改一下
#include<stdio.h>int?g?=?99;
int?main()
{
????static?int?i?=?100;
????return?0;
}
--------------------------------------------------
Linux@dev:~/cStudy$?gcc?memory-test.c?-o?memory-test?&&?size?memory-test
???text????data?????bss?????dec?????hex?filename
???1099?????552??????8?????1659?????67b?memory-test
Linux@dev:~/cStudy$?
初始化后?bss?段變成原來?8?了,?data?段多了?8?個字節。
再修改一下
#include<stdio.h>int?g?;
int?main()
{
????static?int?i?=?100;
????return?0;
}
--------------------------------------------------
Linux@dev:~/cStudy$?gcc?memory-test.c?-o?memory-test?&&?size?memory-test
???text????data?????bss?????dec?????hex?filename
???1099?????548??????12?????1659?????67b?memory-test
Linux@dev:~/cStudy$?
這樣?bss?段和?data?段都比初始值增加了?4?個字節。
5
推薦之前跟這個相關的文章,也是寫?內存?區域的東西,兩篇文章聯系起來看會非常好。
堆和棧的區別(轉過無數次的文章)
還是推薦一下我的知識星球,加入星球的福利我會慢慢增加,當然還是以自愿為主,加入星球了同學,希望還是在星球提問題,這樣的問答環境會更好,也方便追溯問題。
我的知識小密圈
昨天大概看了一下文章的情況,發現收藏的人數很多,但是轉發的人數很少,各位大哥哥,大帥哥,能不能給小弟一點點活路稍微轉發一下,在知乎的時候,就是收藏的數量遠遠超過點贊,已經讓我很傷心了。
完,各位共勉~
總結
- 上一篇: 需要两张图片合成一个PDF文件(两页)
- 下一篇: muse计算机术语,muse2.7制谱软