title: 程序的地址空間
date: 2019-06-10 19:05:33
tags:
- 內存分佈
- C
categories:
- Linux
在《算法設計與分析》這門課裏學了遞歸,但老師只是提了一嘴"遞歸不能太深,否則會棧溢出"。那得多深才溢出啊?爲啥會溢出?得找找資料看看了。下面是我的一些筆記,程序地址空間、進程地址空間……
測試環境centos7 x64。
程序地址空間
根據書上、網上的資料畫個圖,右圖來源linux.cn。
[外鏈圖片轉存失敗(img-fI30Ez28-1563257943127)(https://i.loli.net/2019/06/10/5cfe3f7aa98a142592.png)]
在x86體系結構中分段機制是必選的,而分頁機制則可由具體的操作系統而選擇,Linux通過讓段的基地址爲0而巧妙的繞過了基地址。因此,對於Linux來說,虛地址和線性地址是一致的。在32位的平臺上,線性地址的大小爲固定的4GB。並且,由於採用了保護機制,Linux內核將這4GB分爲兩部分,虛地址較高的1GB(0xC0000000到0xFFFFFFFF)爲共享的內核空間;而較低的3GB(0x00000000到0xBFFFFFFF)爲每個進程的用戶空間。由於每個進程都不能直接訪問內核空間,而是通過系統調用間接進入內核,因此,所有的進程都共享內核空間。而每個進程都擁有各自的用戶空間,各個進程之間不能互相訪問彼此的用戶空間。因此,對於每一個具體的進程而言,都擁有4GB的虛擬地址空間。——百度百科
棧
看到上圖中(linux.cn的那張圖),說棧有8MB,注意是e.g,linux下使用ulimit 命令可以查看系統的很多上限值。
那就來看看啵,ulimit -a
,列出看看。
[parallels@centos-7 vimExercise]$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 7218
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192 # 棧
cpu time (seconds, -t) unlimited
max user processes (-u) 4096
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
[parallels@centos-7 vimExercise]$
他說我現在虛擬機的stack size是8912kb,也就是8MB。那試試咯,試試就試試。
#include <stdio.h>
int cnt = 0;
void func() {
char a[1024 * 1024];
(void) a;
cnt++;
printf("%d MB.\n", cnt);
func();
}
int main() {
func();
return 0;
}
程序輸出
[parallels@centos-7 vimExercise]$ ./stackSizeTest
1 MB.
2 MB.
3 MB.
4 MB.
5 MB.
6 MB.
7 MB.
Segmentation fault (core dumped)
[parallels@centos-7 vimExercise]$
是的,到了7MB再不能申請1MB大小的棧空間了,因爲函數棧幀以及一些別的變量佔去了一部分。
然後我用ulimit -s 2048
,修改棧的限制爲2048kb,試試,不出所料,1MB。
[parallels@centos-7 vimExercise]$ ./stackSizeTest
1 MB.
Segmentation fault (core dumped)
[parallels@centos-7 vimExercise]$
哈哈,以後你再說棧溢出我就改成unlimited。
注意
好吧,剛纔改ulimit 發現改不回來了哈哈哈,它提示我不允許的操作。。。。額。。。。嚇尿了,趕緊sudo,然後提示沒有這條命令????
[外鏈圖片轉存失敗(img-Sg6yqdDq-1563257943129)(https://i.loli.net/2019/06/10/5cfe45b6a8b0231776.png)]
好吧,百度ing……試了煤球用。抱着試一試的心態,先su,然後ulimit,我靠成了就。
百度的過程中學到了,這個值不能指定的太大,否則當併發運行的線程數多時,系統的內存會被衆多thread耗盡。
堆
大大大,很大。能申請多少取決於電腦內存,測試的時候我電腦16GB,申請10GB沒啥毛病(沒別的佔用的情況下,一般系統有你申請他就給你了)。
那麼寫代碼的時候是多多在棧上弄好,還是堆上?
如果是小對象,並且需要頻繁創建和銷燬,在棧上更好。在棧上分配內存更加高效(修改esp寄存器)。
如果是大對象必須在堆上分配。
如果是很大的對象,又要頻繁使用,那就上內存池吧。
剖析內存中的程序之祕 https://linux.cn/article-9255-1.html?pr