Chinaunix

标题: [打印本页]

作者: chenzhanyiczy    时间: 2010-03-17 23:27
标题:
比如A()函数调B()函数,B()函数执行并返回后,原来B()函数中的栈对应的物理内存什么时候回收?
作者: snail_314    时间: 2010-03-17 23:27
回复 31# pengjianbokobe


    默认分配不会是stack_size大小,应该是固定的一个页面大小4k,stack_size是stack所占的vm size允许的最大值。不过我也在想楼上同学的实验,假如随着递归调用分配了3个页面大小的vm,当函数返回到最顶层时,后两个vm会不会被释放掉?虽然释放vm看起来好像没什么意义,但是从安全角度(写代码时也更安全)来说更好一些。
作者: snail_314    时间: 2010-03-17 23:42
函数返回只会将栈指针移动,不会将内存返回内存池。一个进程/线程也就一个栈而已。
作者: accessory    时间: 2010-03-17 23:48
http://bbs.chinaunix.net/viewthread.php?tid=1667231

简单的说,对于WINDOWS下的STDCALL, 是CALLEE (被调用者)回收,对于CDECL 方式的CALL, 是CALLER (调用者)回收。
作者: accessory    时间: 2010-03-17 23:52
回蜗牛兄:
我觉得移动了栈指针之后,就可以看成回收了,因为后面的内容就可以被下次调用的函数覆盖了。
作者: chenzhanyiczy    时间: 2010-03-17 23:59
函数返回只会将栈指针移动,不会将内存返回内存池。一个进程/线程也就一个栈而已。
snail_314 发表于 2010-03-17 23:42



开始我也觉得是这样

但想想,如果B()函数里面有个递归函数C,并且递归了1000次,那么当B()函数返回的时候,此时进程的栈很大了,所对应的物理内存也很大了,

如果全都没有释放的话,感觉有点怪
作者: chenzhanyiczy    时间: 2010-03-18 00:02
回蜗牛兄:
我觉得移动了栈指针之后,就可以看成回收了,因为后面的内容就可以被下次调用的函数覆盖了。
accessory 发表于 2010-03-17 23:52



是回收了,但对应的物理内存是没有释放的,只是被下次调用的函数覆盖了

而现在讲的是 栈对应的物理内存 什么时候释放?
作者: accessory    时间: 2010-03-18 01:45
LZ,你的问题是不是这样的:
LINUX 用户态的栈是可以动态增长的,那么如果只是增长的话,会浪费一些空间,你想问的是什么时候系统会把增长的栈缩小?
作者: re_load    时间: 2010-03-18 09:37
栈的虚拟地址空间是进程运行时分配的,栈的物理页面分配时机是发生缺页异常时。
除非进程over了,物理页面是不会回收的吧,有可能被交换出去。
作者: snail_314    时间: 2010-03-18 09:58
stack应该也不是一直会被缺页异常无穷的分配下去。用ulimit -a可以看到每个进程都有个stack size的限制,当然你也可以把它设为unlimit,也就是说这个stack还是有size概念的,不过是可以动态config的
作者: Godbach    时间: 2010-03-18 10:09
应用态的C程序,通常调用函数返回之后,只是将ESP进行调整。至于栈对应的内存空间,并未立即回收。通常整个主程序退出的时候,会进行处理的。其实这个地方那个,你更需要关注的时候,函数调用返回之后,主程序不要再访问被调用函数的栈空间,访问的结果是未定义的。
作者: re_load    时间: 2010-03-18 10:31
应用态的C程序,通常调用函数返回之后,只是将ESP进行调整。至于栈对应的内存空间,并未立即回收。通常整个 ...
Godbach 发表于 2010-03-18 10:09



嗯,版主说的比较清楚啦。
    栈的虚拟地址空间是进程产生时产生的,每个函数运行时在栈上占用掉一块的空间,有人叫stack frame,
函数运行完毕后这块被占用的栈,被调用者或者自身清除掉,也就是修改一下ESP中的数而已。
在使用虚拟地址空间时,分配到的内存页会在进程结束的时候被释放。没有垃圾回收。
作者: re_load    时间: 2010-03-18 10:45
stack应该也不是一直会被缺页异常无穷的分配下去。用ulimit -a可以看到每个进程都有个stack size的限制,当 ...
snail_314 发表于 2010-03-18 09:58



   是的,绝大部分资源分配都是有个限制的。写个无限递归导致栈溢出,就是虚拟地址空间的溢出,非物理内存分配的溢出。
作者: chenzhanyiczy    时间: 2010-03-18 11:08
LZ,你的问题是不是这样的:
LINUX 用户态的栈是可以动态增长的,那么如果只是增长的话,会浪费一些空间,你 ...
accessory 发表于 2010-03-18 01:45



大概是这意思,这里加个条件---假如栈没有限制的情况下(即stack_size为无限制)
作者: chenzhanyiczy    时间: 2010-03-18 11:08
stack应该也不是一直会被缺页异常无穷的分配下去。用ulimit -a可以看到每个进程都有个stack size的限制,当 ...
snail_314 发表于 2010-03-18 09:58



如果stack size没有限制呢
作者: chenzhanyiczy    时间: 2010-03-18 11:10
应用态的C程序,通常调用函数返回之后,只是将ESP进行调整。至于栈对应的内存空间,并未立即回收。通常整个 ...
Godbach 发表于 2010-03-18 10:09



这个我明白,但我的疑问是,栈对应的物理内存什么时候回收
作者: snail_314    时间: 2010-03-18 11:13
回复 14# chenzhanyiczy


    没试过。但应该会一直缺页异常下去,直到VM size超过2G, segment fault
作者: chenzhanyiczy    时间: 2010-03-18 11:13
是的,绝大部分资源分配都是有个限制的。写个无限递归导致栈溢出,就是虚拟地址空间的溢出,非物理 ...
re_load 发表于 2010-03-18 10:45



如果stack size无限制的时候,假如进程不退出,那么进程栈 占用的物理内存不是很大?
作者: chenzhanyiczy    时间: 2010-03-18 11:14
回复  chenzhanyiczy


    没试过。但应该会一直缺页异常下去,直到VM size超过2G, segment fault
snail_314 发表于 2010-03-18 11:13



2G?不是3G吗?
作者: snail_314    时间: 2010-03-18 11:15
回复 15# chenzhanyiczy


    栈对应的物理内存和你这个进程其他所有的物理内存一样,都是被OS虚拟内存管理器所管理,都纳入swap机制中。和.data, .code没任何区别
作者: chenzhanyiczy    时间: 2010-03-18 11:24
本帖最后由 chenzhanyiczy 于 2010-03-18 11:28 编辑

回复 19# snail_314


    是啊,都是被vma管理的
你的意思是不是这样:
这里假设某进程 没有堆,没有共享空间
.data =1M(VM size)
.code =1M(VM size)
那么栈能占用的 VM size大小为 3G-1M-1M
作者: re_load    时间: 2010-03-18 11:55
如果stack size无限制的时候,假如进程不退出,那么进程栈 占用的物理内存不是很大?
chenzhanyiczy 发表于 2010-03-18 11:13



    linux内核没有物理内存的垃圾回收机制,swap可以看成回收吧。当然交换空间用完了,也就无法继续分配物理内存了。
作者: re_load    时间: 2010-03-18 12:05
如果stack size无限制的时候,假如进程不退出,那么进程栈 占用的物理内存不是很大?
chenzhanyiczy 发表于 2010-03-18 11:13



    会很大的,如果开启了swap机制,其它进程要分配物理页时就会把已被占用的物理页交换出去,然后将该页重分给申请者。
如果这时swap空间用完了,你的进程将会因为分配不到物理页而退出。
如果有很多进程频繁的交换出去而重新分配,系统性能会下降的很厉害,
最明显的体会是系统反应迟缓了,有GUI程序时体会最明显,界面都很难重新刷新,
最糟糕的情况是发生交换抖动,系统基本停止响应。
作者: re_load    时间: 2010-03-18 12:11
如果stack size没有限制呢
chenzhanyiczy 发表于 2010-03-18 11:08



    上面说的是开启swap机制时的情况,如果没有开启swap机制,申请到多少物理页就使用多少物理页了,
如果其他进程再申请物理页,能分配则分配,不能分配将会因分配不到内存页退出。
作者: re_load    时间: 2010-03-18 12:19
在不开启swap时,进程结束时回收。
在开始swap时,当其它进程申请物理页而没有足够的物理页时,通过swap机制,交换到磁盘上的方式回收。
作者: snail_314    时间: 2010-03-18 12:45
回复 20# chenzhanyiczy


    应该是。这是最大值。初始化时不可能分配这么大,是缺页异常动态分配的。
作者: goldenfort    时间: 2010-03-18 16:57
当 函数调用, 栈顶指针 超过当前进程 已经 分配的page时, 发生缺页中断, 系统 为其分配一个物理页, 栈可以继续增长。

当 函数调用返回, 栈顶指针 缩回去 , 导致原来分配的页, 很长时间没有被读取时,   如果其它进程 发生缺页, 根据页面分配算法,
很长时间没有被读的栈页有可能被 直接分配给别的进程, 因为超过栈顶指针的页, 应该不算dirty页, 不用swap.


其实本质还是 页面分派算法,  如果一个页很长时间没有使用, 又没有有意义的数据, 接直接分派给别的需要的进程。
作者: chenzhanyiczy    时间: 2010-03-18 18:02
本帖最后由 chenzhanyiczy 于 2010-03-18 21:06 编辑


作者: babywolfh    时间: 2010-03-18 20:42
物理内存应该在进程退出时回收吧
作者: re_load    时间: 2010-03-18 20:47
问题来了,呵呵

环境:
Linux crmop 2.6.18-53.el5xen #1 SMP Wed Oct 10 17:06:12 EDT 2007 i686 athlo ...
chenzhanyiczy 发表于 2010-03-18 18:02



   晕,
  1.    printf("somewhere's value is %c\n",*(a+3024));
  2.    printf("somewhere's address is %p\n",a+3024);
复制代码
这两句是错误的。a+3024越界了。
  首先栈是向下增长的,你用a+3024,想搞溢出攻击吗,嘿嘿
作者: chenzhanyiczy    时间: 2010-03-18 21:08
回复 29# re_load

谢谢提醒
哎。。。
脑子进水了,明天去测试下栈增长的情况
作者: pengjianbokobe    时间: 2010-03-19 10:28
我想知道操作系统为一个进程默认分配的stack_size大小的栈和因为缺页异常而增加的新的物理页,都是在进程结束之后free的吗?还有就是怎么释放的?对相关的页表进行修改即可?O(∩_∩)O谢谢
作者: 瀚海书香    时间: 2010-03-19 15:36
回复 1# chenzhanyiczy
哦。明白了。默认的stack size在linux下一般是8M还是跟内存有关啊?
作者: chenzhanyiczy    时间: 2010-03-19 17:53
回复 33# 瀚海书香


    8M
跟内存有什么关系




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2