[CPyUG] 请教下Python下的内存释放方式

0 views
Skip to first unread message

Don

unread,
Sep 26, 2011, 5:47:50 AM9/26/11
to python-cn(华蟒用户组,CPyUG 邮件列表)
根据我测试下来的结果是,Python不释放申请到的内存。

但一个长期运行(最少一个星期)的daemon程序中,内存会不断增长而影响其他进程的内存分配。

最近一段时间一直苦恼于有无比较好的方法,哪怕是定时的让python释放空闲内存到系统也好。

请各位有经验的同学多支支招。

谢谢。

--
来自: python-cn`CPyUG`华蟒用户组(中文Python技术邮件列表)
发言: pyth...@googlegroups.com
退订: python-cn+...@googlegroups.com (向此发空信即退!)
详情: http://code.google.com/p/cpyug/wiki/PythonCn
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
强烈: 建议使用技巧: 如何有效地报告Bug
http://www.chiark.greenend.org.uk/%7Esgtatham/bugs-cn.html

lu_zi_2000

unread,
Sep 26, 2011, 6:03:55 AM9/26/11
to pyth...@googlegroups.com
这个我研究过,基本上没办法。已经被申请的内存不会被释放,而是放到缓存中=
下次使用。
我现在用的办法是定期重起。。。
如果你有好的办法,请分享分享。

Don

unread,
Sep 26, 2011, 7:56:07 AM9/26/11
to python-cn(华蟒用户组,CPyUG 邮件列表)
我也想由额外进程监控并定期重启的。
但还要考虑维持与大量客户端的TCP长连。

机械唯物主义 : linjunhalida

unread,
Sep 26, 2011, 8:51:03 AM9/26/11
to pyth...@googlegroups.com
请问下在维持大量tcp长连接的时候怎么做切换呢?

2011/9/26 Don <donn...@gmail.com>:

Don

unread,
Sep 26, 2011, 10:31:48 AM9/26/11
to python-cn(华蟒用户组,CPyUG 邮件列表)
就是因为TCP长连要维持,不能切换,所以,python的内存释放,难倒我了呀。

Shell Xu

unread,
Sep 26, 2011, 10:57:02 AM9/26/11
to pyth...@googlegroups.com
有个折中方案是新开一个进程,负责新连接,然后老进程停止accept,处理的连接数小于一定值就自杀。
其实在tcp编程上,可重连是一个重要考虑。把希望寄托在tcp不会中断上不是很可靠。
--
无能者无所求,饱食而遨游,泛若不系之舟
blog: http://shell909090.com/blog/
twitter: http://twitter.com/shell909090

MuSheng Chen

unread,
Sep 26, 2011, 9:26:48 PM9/26/11
to pyth...@googlegroups.com
一直也關注python內存釋放問題.
剛想到了個辦法,利用系統釋放內存.
分別使用"linux釋放內存"和"windows釋放內存"關鍵字,在gg找到的內容.
利用系統管理工具對已分配但不被使用的內存進行回收.

http://www.linuxidc.com/Linux/2008-01/10738.htm
http://bbs.chinaunix.net/thread-2195511-1-1.html

http://blog.5dmail.net/user1/31/53.html
http://www.ithov.com/article/winsystem/winthree/64017.shtml

每隔一段時間做一次系統內存回收,這樣我們就不用糾結於使用python來釋放內存.
長鏈接也不用成為杯具了.


2011/9/26 Shell Xu <shell...@gmail.com>

机械唯物主义 : linjunhalida

unread,
Sep 26, 2011, 9:29:15 PM9/26/11
to pyth...@googlegroups.com
恩, 这个也挺好的, 前几天看unicorn介绍, 就是建立一个unix socket, 若干worker进程select这个socket来工作的.
unicorn就是ruby里面的那个unicorn....

2011/9/26 Shell Xu <shell...@gmail.com>:


> 有个折中方案是新开一个进程,负责新连接,然后老进程停止accept,处理的连接数小于一定值就自杀。
> 其实在tcp编程上,可重连是一个重要考虑。把希望寄托在tcp不会中断上不是很可靠。
>

机械唯物主义 : linjunhalida

unread,
Sep 26, 2011, 9:29:58 PM9/26/11
to pyth...@googlegroups.com
python下面应该也有类似工具吧, 省得自己来管了.

2011/9/27 机械唯物主义 : linjunhalida <linjun...@gmail.com>:
> unicorn

Shell Xu

unread,
Sep 26, 2011, 9:35:54 PM9/26/11
to pyth...@googlegroups.com
真正的长连接,要通过这种方式进行保持也挺麻烦的。因为每链接持续处理的模式就变成了每数据包处理的模式,并且随时可能重启进程,自己不但要管理上下文,还得负责上下文持久化和持久化。
--
无能者无所求,饱食而遨游,泛若不系之舟
blog: http://shell909090.com/blog/
twitter: http://twitter.com/shell909090

Shell Xu

unread,
Sep 26, 2011, 9:41:21 PM9/26/11
to pyth...@googlegroups.com
windows的不去说他,第一个说linux cache drop那个明显是windows用户写的。好好的cache,基本等效于空闲内存。在申请的时候会自动释放,没事的时候还可以加速磁盘读。非要给全释放了,好让机器的内存计数看起来好看点。。。
另外,python的内存不释放问题有部分来源于内存模型,另外部分来源于对象缓存(就是free_list),两者都属于活跃内存,没法释放的。

Marlon Yao

unread,
Sep 26, 2011, 10:11:57 PM9/26/11
to pyth...@googlegroups.com
是rss,还是只是虚存在增加?如果是rss不断增加,应该是内存泄露的问题。

2011/9/26 Don <donn...@gmail.com>

Shell Xu

unread,
Sep 26, 2011, 11:10:35 PM9/26/11
to pyth...@googlegroups.com
从python内存管理模型的特性上推算,应当是RSS。原因我正在写文,明天发出来。
--
无能者无所求,饱食而遨游,泛若不系之舟
blog: http://shell909090.com/blog/
twitter: http://twitter.com/shell909090

Shell Xu

unread,
Sep 27, 2011, 10:14:24 PM9/27/11
to pyth...@googlegroups.com

Marlon Yao

unread,
Sep 28, 2011, 12:15:40 AM9/28/11
to pyth...@googlegroups.com
感觉你的标题有点误导吧,python绝大数情况下会释放分配的内存。

至于文章中说的不分配的情况,在实际应用中比较少见。java明显占用比python要高。java的内存释放做得要比python好。

几点注释:
1. java比python更耗内存,最起码初始内存java明显占用比python要高。java的内存释放做得要比python好。

2. linux下堆栈大小是可以动态扩展的,即使初始值8M,也可以分配大于8M的对象。windows下就不清楚,难道windows下栈不能自动扩展?

3.
也就是说,如果我们运气比较差,申请了10个对象,偏偏每个对象大小差8字节。这样系统就要给我们分配10个堆,而不是刚刚好。如果你的对象粒度都比较散,那么内存开销比较大也不奇怪。
“内部碎片”在所有动态分配内存方法中都存在这个问题,包括malloc。

对楼主的问题,可能更多还是应用本身的问题,而不是python内存释放机制的问题。

2011/9/28 Shell Xu <shell...@gmail.com>

Don

unread,
Sep 28, 2011, 5:24:03 AM9/28/11
to python-cn(华蟒用户组,CPyUG 邮件列表)
感谢各位的回复。

首先,fork进程去接受新连接,或类似的解决方案貌似好复杂。

另外,我写了个测试代码,地址:
http://www.cnitblog.com/donne/archive/2011/09/28/75671.html

这个在CentOS下跑出来的结果跟我们项目中发现的现象很相近。
我非常赞成Shell Xu的观点:

python下还有一个更坑爹的事情,也是大部分内存不释放的根本原因。在int/str等对象的模块中,有个模块级别的对象缓存链表,static
PyObject * free_list。当对象释放的时候,压根不会还到池中,而是直接在free_list中缓存。根据我的搜索,python内
部没有地方对此进行干预。

我觉得这个是产生这个问题的根本原因。
内存一直往上飘,用meliae却看不到异常。

Leo Jay

unread,
Sep 28, 2011, 5:31:07 AM9/28/11
to pyth...@googlegroups.com
2011/9/28 Don <donn...@gmail.com>:

> 感谢各位的回复。
>
> 首先,fork进程去接受新连接,或类似的解决方案貌似好复杂。
>
> 另外,我写了个测试代码,地址:
> http://www.cnitblog.com/donne/archive/2011/09/28/75671.html
>
> 这个在CentOS下跑出来的结果跟我们项目中发现的现象很相近。
> 我非常赞成Shell Xu的观点:
> “
> python下还有一个更坑爹的事情,也是大部分内存不释放的根本原因。在int/str等对象的模块中,有个模块级别的对象缓存链表,static
> PyObject * free_list。当对象释放的时候,压根不会还到池中,而是直接在free_list中缓存。根据我的搜索,python内
> 部没有地方对此进行干预。
> ”
>
> 我觉得这个是产生这个问题的根本原因。
> 内存一直往上飘,用meliae却看不到异常。
>

我不是很同意这种看法。
如果说你们内存使用一直在稳定增加,应该不是这里的问题。

python只是缓存起来,并不是真的泄露了。如果你后面要生成对象的时候,python不会向系统申请内存,
而是直接从缓存里拿对象来用。
除非你们的应用本来就是随着时间的增加,申请的对象也越来越多,不然内存占用增长到一定量之后应该会稳定才对。

我建议你们查查是不是有哪些对象明明没用了,却还被引用着,没有释放。

--
Best Regards,
Leo Jay

Shell Xu

unread,
Sep 28, 2011, 10:14:50 AM9/28/11
to pyth...@googlegroups.com
如果内存一直在上涨,那绝对不是free_list的问题。free_list是内存不再释放的理由,而不是内存上涨的理由。如果你们的内存使用不断上涨,那必然是引用的对象在逐步增加。
对了,还有一个内存不释放的原因。在原来的源码中,dict/set之类的hash table,在装载率高于3/4后,会自动扩展一次空间。而当数据逐步清空时,却不会自动shrink。如果把一堆数据放入一个dict,然后再逐步清理后,这个dict是不会释放空间的。不知道新版本中这个问题修正没有。
--
无能者无所求,饱食而遨游,泛若不系之舟
blog: http://shell909090.com/blog/
twitter: http://twitter.com/shell909090

Shell Xu

unread,
Sep 28, 2011, 10:10:58 AM9/28/11
to pyth...@googlegroups.com
在 2011年9月28日 下午12:15,Marlon Yao <yaol...@gmail.com>写道:
感觉你的标题有点误导吧,python绝大数情况下会释放分配的内存。

至于文章中说的不分配的情况,在实际应用中比较少见。java明显占用比python要高。java的内存释放做得要比python好。

几点注释:
1. java比python更耗内存,最起码初始内存java明显占用比python要高。java的内存释放做得要比python好。
所以我说,真的需要关注内存,最起码用java,或者干脆用C。 

2. linux下堆栈大小是可以动态扩展的,即使初始值8M,也可以分配大于8M的对象。windows下就不清楚,难道windows下栈不能自动扩展?
linux的栈自动扩展机制不是很熟悉,windows叫做预分配机制。即预先分配1M的地址空间,然后不分配实际的内存,直到第一次使用这个内存区域,产生页面错误为止。如果使用的地址空间大于1M,那就不再捕获错误并且自动分配内存,而是抛出地址访问异常。linux的默认栈大小是可以修改的,通过ulimit。而ulimit又受到pam的限制。但是我怀疑linux的栈是否能动态扩展,因为大量扩展栈地址是会发生问题的。

3.
也就是说,如果我们运气比较差,申请了10个对象,偏偏每个对象大小差8字节。这样系统就要给我们分配10个堆,而不是刚刚好。如果你的对象粒度都比较散,那么内存开销比较大也不奇怪。
“内部碎片”在所有动态分配内存方法中都存在这个问题,包括malloc。
说对了,所以要在C里面关注内存,有的时候都没法用malloc。C++的alloctor很多时候需要通过定制来解决一些问题,也是基于类似理由。 

Shell Xu

unread,
Sep 28, 2011, 10:11:52 AM9/28/11
to pyth...@googlegroups.com
在下面的评论中有说到,最关键的一点free_list在2.6以后就开始自动回收了。如果你使用2.6以上版本,没有这个问题。
--
无能者无所求,饱食而遨游,泛若不系之舟
blog: http://shell909090.com/blog/
twitter: http://twitter.com/shell909090

feiping tu

unread,
Sep 28, 2011, 9:15:34 PM9/28/11
to pyth...@googlegroups.com
应该是释放的对象还有引用,导致python不能释放内存,个人感觉python不应该放着这么明显的问题不处理的。
--
From 涂飞平
tufeiping AT gmail.com

Marlon Yao

unread,
Sep 29, 2011, 12:58:27 AM9/29/11
to pyth...@googlegroups.com
2. linux下堆栈大小是可以动态扩展的,即使初始值8M,
也可以分配大于8M的对象。windows下就不清楚,难道windows下栈不能自动扩展?
linux的栈自动扩展机制不是很熟悉,windows叫做预分配机制。即预先分配1M的地址空间,然后不分配实际的内存,直到第一次使用这个内存区域,产生页面错误为止。如果使用的地址空间大于1M,那就不再捕获错误并且自动分配内存,而是抛出地址访问异常。linux的默认栈大小是可以修改的,通过ulimit。而ulimit又受到pam的限制。但是我怀疑linux的栈是否能动态扩展,因为大量扩展栈地址是会发生问题的。

嗯,这部分我说得有点问题。linux堆栈的确是动态扩展的,但初始值不是8M。我写了一个递归调用的小程序,然后拿pmap去观察分配的堆栈大小,其堆栈初始大小84K,随着程序运行堆栈大小会增加,但最多只能增加到8M,也就是ulimit限制。

2011/9/28 Shell Xu <shell...@gmail.com>

Marlon Yao

unread,
Sep 29, 2011, 12:58:32 AM9/29/11
to pyth...@googlegroups.com
2. linux下堆栈大小是可以动态扩展的,即使初始值8M,
也可以分配大于8M的对象。windows下就不清楚,难道windows下栈不能自动扩展?
linux的栈自动扩展机制不是很熟悉,windows叫做预分配机制。即预先分配1M的地址空间,然后不分配实际的内存,直到第一次使用这个内存区域,产生页面错误为止。如果使用的地址空间大于1M,那就不再捕获错误并且自动分配内存,而是抛出地址访问异常。linux的默认栈大小是可以修改的,通过ulimit。而ulimit又受到pam的限制。但是我怀疑linux的栈是否能动态扩展,因为大量扩展栈地址是会发生问题的。

嗯,这部分我说得有点问题。linux堆栈的确是动态扩展的,但初始值不是8M。我写了一个递归调用的小程序,然后拿pmap去观察分配的堆栈大小,其堆栈初始大小84K,随着程序运行堆栈大小会增加,但最多只能增加到8M,也就是ulimit限制。

2011/9/28 Shell Xu <shell...@gmail.com>


Reply all
Reply to author
Forward
0 new messages