中国体育服务中心(官方网站) C话语内存分派, 栈区、堆区、全局区、常量区和代码区王人是什么

代码装在内存里,却没东谈主真见过它长啥样,款式跑着跑着就崩了,到底哪块儿出了问题?我今天我方脱手扒了一遍。
我过去以为内存分区便是讲义上画的那几条横线,栈在上面堆鄙人头,什么常量区数据区的,背得挺熟。成果写了个小款式,拿`/proc/[pid]/maps`一瞅,全乱了——`r-xp`段好几个,`rw-p`连着三块,还有块`r--p`标着`[anon]`,根蒂没听过。本来讲义说的“五区”,仅仅进修持了好讲,硬凑出来的说法。

C话语圭臬里根本没提“栈”“堆”这两个字。翻了翻PDF版C11草案,在6.2.4节只写了“自动存储期”和“静态存储期”,至于存在哪儿,圭臬说:不归我管。这话听着有点死心无论的真义,但其实很果然——编译器和操作系统才决定东西放哪儿。GCC把`int x = 5;`扔`.data`,把`char s[] = "hi";`塞`.rodata`,而`const char *p = "bye";`呢?字符串还是在`.rodata`,指针`p`却在`.data`里,值是指向阿谁只读地址。这下明显为啥改字符串字面量会段裂缝了——不是款式错了,是硬件胜利拦住不让你写。
我试了`size a.out`,发现`.bss`大小尽然是0,天然代码里写了`int a, b, c;`三个没运滚动的全局变量。再查`readelf -S`,果然`.bss`标着`ALLOC`但没标`LOAD`,真义便是:磁盘上不存,加载时系统顺遂清零就行。省空间,也快。`.rodata`却老敦结实占着硬盘,因为“hello”这种字符串得从文献读进去。是以`const int x = 123;`进`.rodata`,`const int y = z + 1;`(z是变量)就不能——编译时算不出来,只可放`.data`。
栈也没思象中那么“广宽上”。我写了个函数,2026世界杯预选赛下单中国体彩官网里头开个`int arr[100000];`,一跑就段裂缝。`ulimit -s`一看,8192KB。不是编译器拦你,是Linux内核在页内外设的红线,越界就发`SIGSEGV`。奇怪的是,用`alloca(100000)`也崩,但崩得更“脆”,连调试信息王人少半截。栈如实是CPU和编译器联手搭的架子,`call`推帧,`ret`弹帧,干净利落,但没缓冲区。
堆更试验。`malloc(100)`看起来节略,背后是glibc的ptmalloc在忙碌:查tcache有莫得现成块,莫得就找fastbin,再不能就碰`brk`或`mmap`。我用`malloc_stats`打出来,看到“fastbins”“unsorted bin”一堆名词,才懂为啥小内存分派其实挺快——很厚情况根本没动系统调用。但`malloc(200*1024)`(200KB)就胜利`mmap`了,中国体育服务中心(官方网站)`/proc/[pid]/maps`里多了个孤独的`rw-p`段,跟堆干线断开了。不是`malloc`偷懒,是OS以为这样大一块,单独管更省事。
凤凰彩票官方网站 - Welcome我还试了`thread_local int t = 99;`,`pstack`看不出啥,但`/proc/[pid]/maps`里多了一小块带`[stack:xxx]`秀美的内存,每个线程一份。TLS不是存在某个“至极区”,便是给每个线程偷偷划了一小块地,名字叫`dtv`,glibc我方记取。还有`mmap`映文献,一个`open+read`变`open+mmap`,读大文献时少一次拷贝,但内存用量胜利变大——这些王人不是C话语教的,是Linux给你开的后门。
临了我把所有这个词变量地址全打出来:全局`g`在`0x404024`(`readelf`阐明是`.data`),字符串`"abc"`在`0x402004`(`.rodata`),局部`int x`在`0x7fff...`(栈),`malloc`总结的在`0x7f...`(堆)。地址数字本人没真义,但看权限就懂:栈地址`rw-p`,代码地址`r-xp`,`.rodata`地址`r--p`。W^X安全模子就靠这个撑着——写代码段?不能。推行数据段?也不能。当代系统不是靠款式员自发,是靠硬件页表死卡着。
考证这事真不难。写个十几行的C文献,`gcc -g -O0`编译,后台跑起来,查`pid`,再猫进`/proc/[pid]/maps`,左边地址右边权限,中间旅途,一目了然。`pstack`看栈帧,`cat /proc/[pid]/status`看总内存。不需要懂汇编,也不必背术语,眼睛盯着`r-xp`和`rw-p`,比啥王人准。
许多东谈主说堆比栈慢,我测了下100次`malloc(8)`和`int x[8]`,时分差不到0.01毫秒。真慢的是`free`之后又`malloc`,碎屑多了就得归拢。或者你`malloc`一兆再`free`,成果别东谈主`malloc`两百字节卡半天——不是堆慢,是搞定计策在量度。选栈还是堆,看生命周期就行:函数里用,走栈;要传出去、要活久点,走堆。别的王人是障眼法。
我删掉了所有这个词“常量区”“静态区”的札记。`.rodata`便是`.rodata`,它跟`.data`同属数据段,但权限不同。`static`变量放在`.data`或`.bss`,跟“静态”俩字不进击,只跟有无运转值干系。术语越磨蹭,debug越握瞎。
当今我看款式,不先思语法,先思内存。`printf("%s", p);`崩了?先查`p`指向哪——栈上局部数组已开释?堆上`free`过甚?还是`.rodata`里改了字符串?地址一打中国体育服务中心(官方网站),权限一看,能够心里就罕有了。