java如何手动释放内存Python的内存

2283人阅读
编程珠玑(4)
在maillist里面看到无数次的有人问,python速度为什么这么慢,python内存管理很差。实话说,我前面已经说过了。如果你在意内存/CPU,不要用python,改用C吧。就算C不行,起码也用个go或者java。不过今天还是说说,python的内存为什么不释放。
& & 首先,python的初始内存消耗比C大,而且大很多。这个主要来自python解释器的开销,没什么好解释的。用解释器,就得承担解释器运行开销。然后,python中的每个对象,都有一定的对象描述成本。因此一个long为例,在C下面一般是4个字节(不用int是因为int在不同平台下是变长的),而python下面至少是16个字节。如果你生成100W个对象,那么C的内存消耗是4M,python的是16M。这些都是常规内存消耗,搞不明白的就别问了,不再解释。
&&& 下面解释一下python的内存释放情况。
&&& 如果是C,通常是用long array[1024 * 1024]的方法来生成1M个对象空间。当然,实际这样是不一定能运行的。因为linux的默认栈空间是8M,而Windows默认栈空间只有1M。所以代码在linux下可以通过,而windows下会跑爆掉。怎么办?下面说。当这个函数执行完毕后,当RET的时候,会自动退栈,空间就会自动释放掉(虽然在逻辑上这部分空间还是保留没有释放的,然而空间不活跃了,不过统计的时候还是占用的)。当然,更好的办法是使用malloc。malloc会从系统中自动提取和管理空间,free自动释放。这样无论是linux还是windows,都没有栈空间不足的问题。free后就会自动交还系统(4M已经超过了交还的最大阀值,一般glibc不会自己闷掉不交给系统的)。如果你忘记free,这部分内存就会一直占用,直到进程退出未知,这就是很有名的内存泄露。
&&& python下的情况更加复杂一些,python没有直接使用malloc为对象分配细粒度内存,而是使用了三层堆结构,加上三色标记进行回收。所谓三层堆,细节我们不说了,在源码阅读笔记里面写的比较详细。但是有一点需要我们记住的——当我们分配某个大小的内存的时候,内存管理器实际上是向上对齐到8字节,然后去对应的内存池中切一块出来用的。也就是说,如果我们运气比较差,申请了10个对象,偏偏每个对象大小差8字节。这样系统就要给我们分配10个堆,而不是刚刚好。如果你的对象粒度都比较散,那么内存开销比较大也不奇怪。
&&& python下还有一个更坑爹的事情,也是大部分内存不释放的根本原因。在int/str等对象的模块中,有个模块级别的对象缓存链表,static PyObject * free_list。当对象释放的时候,压根不会还到池中,而是直接在free_list中缓存。根据我的搜索,python内部没有地方对此进行干预。就是说,一旦你真的生成了1M个数字对象,然后释放。这1M个对象会在free_list链表中等待重用,直到天荒地老,这16M内存压根不会返还。而且,int的对象缓存链表和str的还不通用。如果你又做了1M个str对象,他的开销还是会继续上涨。几乎所有的内建对象都有这种机制,因此对于大规模对象同时生成,python会消耗大量内存,并且永不释放。
&&& 解决的机制,基本只有用yield来将列表对象转换为生成器对象。列表对象会同时生成所有元素,从而直接分配所有内存。而生成器则是一次生成一个元素,比较节约内存。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:49166次
排名:千里之外
转载:41篇
(1)(3)(1)(26)(15)13644人阅读
Linux(20)
一台老的PHP后台服务器,今天用 free -m 查看,发现内存跑满了。
再 top,然后按下shift+m,也就是按内存占用百分比排序,发现排在第一的进程,才占用0.9%,那是什么占用的呢?谷歌了一下,据说是centos为了提高效率,把部分使用过的文件缓存到了内存里。如果是这样的话,我又不需要这样的文件性能,那就可以释放。如下两个命令就可以:
#echo 3 & /proc/sys/vm/drop_caches
内存释放后,就占用很低了,如下:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1672770次
积分:11905
积分:11905
排名:第848名
原创:155篇
评论:284条
(1)(1)(2)(3)(3)(1)(4)(2)(3)(2)(3)(1)(3)(1)(4)(1)(4)(3)(3)(4)(7)(4)(5)(2)(6)(2)(2)(5)(2)(7)(12)(1)(2)(3)(2)(1)(1)(8)(3)(9)(2)(3)(1)(2)(3)(4)(4)(2)(4)(2)(2)(3)如何释放Python占用的内存?
最近刚刚接触python,整天开着shell对着网站和书本输命令,但是输着输着我就有了一个疑问,输入进去的这些指令和指令运算的结果都是存在哪里的?当我退出shell(指令都输在shell里面并没有往sublime里面写)后,这些指令和结果占用的内存会不会被释放?在matlab这些软件里面我们可以使用一个非常简单的clear来清空变量,python呢?求解答哈
这是关于Python的垃圾回收机制的问题。Python用了引用计数的方法,每有一个指针引用了一个变量,计数就+1,取消引用则-1。当某块变量的引用计数为0时,它就自动地被回收了。话说Python明明就有del命令好吧……
试一下&&& from pympler import tracker
&&& import random
&&& tr = tracker.SummaryTracker()
&&& a = [[random.random() for i in range(2000)] for i in range(2000)]
&&& tr.print_diff()
# objects |
total size
========================================================== | =========== | ============
&class 'pyreadline.lineeditor.lineobj.ReadLineTextBuffer |
wrapper_descriptor |
getset_descriptor |
member_descriptor |
function (store_info) |
&&& import gc
&&& gc.collect()
&&& from sys import getsizeof
&&& getsizeof(a)
用getsizeof(a) 取到的只是a一个list的object的大小 实际的大小要加上a里的4000000个float和2000个list的大小 所以这个2000 * 2000的list大小应该是120多mb gc也没什么好collect的想要占的少一点 最简单的方法是 用Numpy&&& tr = tracker.SummaryTracker()
&&& a = array([[random.random() for i in range(2000)] for i in range(2000)])
&&& tr.print_diff()
# objects |
total size
========================================================== | =========== | ============
numpy.ndarray |
&class 'pyreadline.lineeditor.lineobj.ReadLineTextBuffer |
wrapper_descriptor |
getset_descriptor |
member_descriptor |
function (store_info) |
没有在交互模式定义函数、类之类的话,直接生成的对象的引用一直存在,不会被gc。可以输入dir() 查看一下所有变量,del 你自己的变量。也可以直接退出python进程,操作系统会回收内存的。
LS 有人提到了引用计数,这是 Python 的垃圾回收策略。补充一下。解释器(也就是你说的 Shell)负责跟踪对象的引用计数,垃圾收集器负责释放内存。如何释放?可以通过销毁对象的引用,使引用计数减少至 0。假设 x = 3,以下情况会使 3 这个整型对象的引用计数减少;
函数运行结束,所有局部变量都被销毁,对象的引用计数也就随之减少。例如 foo(x) 运行结束,x 被销毁;
当变量被赋值给另一个对象时,原对象的引用计数也会减少。例如 x = 4,这时候 3 这个对象的引用计数就减 1 了;使用 del 删除一个变量也会导致对象引用减少。例如 del x;对象从集合对象中移除。例如 lst.remove(x);包含对象的集合对象被销毁。例如 del lst;这些操作都可能使对象变成垃圾回收对象,由垃圾收集器负责收集,当然垃圾收集器也负责处理循环引用对象。
已有帐号?
无法登录?
社交帐号登录

我要回帖

更多关于 python 强制释放内存 的文章

 

随机推荐