在《算法设计与分析》这门课里学了递归,但老师只是提了一嘴”递归不能太深,否则会栈溢出”。那得多深才溢出啊?为啥会溢出?得找找资料看看了。下面是我的一些笔记,程序地址空间、进程地址空间……
测试环境centos7 x64。
程序地址空间
根据书上、网上的资料画个图,右图来源linux.cn。
在x86体系结构中分段机制是必选的,而分页机制则可由具体的操作系统而选择,Linux通过让段的基地址为0而巧妙的绕过了基地址。因此,对于Linux来说,虚地址和线性地址是一致的。在32位的平台上,线性地址的大小为固定的4GB。并且,由于采用了保护机制,Linux内核将这4GB分为两部分,虚地址较高的1GB(0xC0000000到0xFFFFFFFF)为共享的内核空间;而较低的3GB(0x00000000到0xBFFFFFFF)为每个进程的用户空间。由于每个进程都不能直接访问内核空间,而是通过系统调用间接进入内核,因此,所有的进程都共享内核空间。而每个进程都拥有各自的用户空间,各个进程之间不能互相访问彼此的用户空间。因此,对于每一个具体的进程而言,都拥有4GB的虚拟地址空间。——百度百科
栈
看到上图中(linux.cn的那张图),说栈有8MB,注意是e.g,linux下使用ulimit 命令可以查看系统的很多上限值。
那就来看看啵,ulimit -a
,列出看看。
1 | [parallels@centos-7 vimExercise]$ ulimit -a |
他说我现在虚拟机的stack size是8912kb,也就是8MB。那试试咯,试试就试试。
1 |
|
程序输出
1 | [parallels@centos-7 vimExercise]$ ./stackSizeTest |
是的,到了7MB再不能申请1MB大小的栈空间了,因为函数栈帧以及一些别的变量占去了一部分。
然后我用ulimit -s 2048
,修改栈的限制为2048kb,试试,不出所料,1MB。
1 | [parallels@centos-7 vimExercise]$ ./stackSizeTest |
哈哈,以后你再说栈溢出我就改成unlimited。
注意
好吧,刚才改ulimit 发现改不回来了哈哈哈,它提示我不允许的操作。。。。额。。。。吓尿了,赶紧sudo,然后提示没有这条命令????
好吧,百度ing……试了煤球用。抱着试一试的心态,先su,然后ulimit,我靠成了就。
百度的过程中学到了,这个值不能指定的太大,否则当并发运行的线程数多时,系统的内存会被众多thread耗尽。
堆
大大大,很大。能申请多少取决于电脑内存,测试的时候我电脑16GB,申请10GB没啥毛病(没别的占用的情况下,一般系统有你申请他就给你了)。
那么写代码的时候是多多在栈上弄好,还是堆上?
如果是小对象,并且需要频繁创建和销毁,在栈上更好。在栈上分配内存更加高效(修改esp寄存器)。
如果是大对象必须在堆上分配。
如果是很大的对象,又要频繁使用,那就上内存池吧。
剖析内存中的程序之秘 https://linux.cn/article-9255-1.html?pr