程序的地址空間


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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章