怎么解决python的gifview解决内存泄露露问题

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
您的访问请求被拒绝 403 Forbidden - ITeye技术社区
您的访问请求被拒绝
亲爱的会员,您的IP地址所在网段被ITeye拒绝服务,这可能是以下两种情况导致:
一、您所在的网段内有网络爬虫大量抓取ITeye网页,为保证其他人流畅的访问ITeye,该网段被ITeye拒绝
二、您通过某个代理服务器访问ITeye网站,该代理服务器被网络爬虫利用,大量抓取ITeye网页
请您点击按钮解除封锁&新版 ChinaUnix 客户端强势归来!
扫描二维码安装
扫描二维码安装
支持分类信息/主题分类
支持搜索/分享/删选/注册
社区新帖热帖实时更新
所有数据和网站实时同步
查看周边用户、周边帖子
查看网友发帖位置
随时随地拍照上传
可多选5张照片
轻松录音上传
倾听ta的声音
回复信息及时通知
和好友实时语音交流
北京皓辰网域网络信息技术有限公司. 版权所有 京ICP证:060528号 北京市公安局海淀分局网监中心备案编号:
广播电视节目制作经营许可证(京) 字第1234号
中国互联网协会会员&&联系我们:
感谢所有关心和支持过ChinaUnix的朋友们
转载本站内容请注明原作者名及出处粗略分析Python中的内存泄漏
作者:C Wong
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了粗略分析Python中的内存泄漏,分析了包括在垃圾回收时产生等的原因,需要的朋友可以参考下
之前一直盲目的认为 Python 不会存在内存泄露, 但是眼看着上线的项目随着运行时间的增长 而越来越大的内存占用, 我意识到我写的程序在发生内存泄露, 之前 debug 过 logging 模块导致的内存泄露.
目前看来, 还有别的地方引起的内存泄露. 经过一天的奋战, 终于找到了内存泄露的地方, 目前项目 跑了很长时间, 在业务量较小的时候内存还是能回到刚启动的时候的内存占用.
什么情况下不用这么麻烦
如果你的程序只是跑一下就退出大可不必大费周章的去查找是否有内存泄露, 因为 Python 在退出时 会释放它所分配的所有内存, 如果你的程序需要连续跑很长时间那么就要仔细的查找是否 产生了内存泄露.
如何产生的内存泄露呢, 项目是一个 TCP server, 每当有连接过来时都会创建一个连接实例来进行 管理, 每次断开时连接实例还被占用并没有释放. 没有被释放的原因肯定是因为有某个地方对连接 实例的引用没有释放, 所以随着时间的推移, 连接创建分配内存, 连接断开并没有释放掉内存, 所以 就会产生内存泄露.
由于不知道具体是哪里引起的内存泄露, 所以要耐心的一点点调试.
由于知道了断开连接时没有释放, 所以我就不停的模拟创建连接然后发送一些包后断开连接, 然后通过下面一行 shell 来观察内存占用情况:
PID=50662; ps aux | grep $PID | grep -v grep | awk '{print $5" "$6}' && sleep 1; done
如果在增长了一定的量后保持住就说明已经没有产生泄露.
同时可以在对象该释放的时候查看对象的引用计数, 通过 sys.getrefcount(obj). 如果引用计数变为了 2 则说明该对象在跳出命名空间后就会被正确回收.
项目中两种情况导致对象没有被正确回收:
&&& 被退出才回收的对象引用
&&& 交叉引用
被退出才回收的对象引用
为了追踪连接所以把连接对象同时放在一个列表里, 而这个列表只有在程序退出时才会被回收, 如果不正确处理, 那么分配的对象将也会只在程序退出时才会被回收.
全局变量和类变量都只会在程序退出的时候才会被回收:
_CONNECTIONS = []
class Connection(object):
def __init__(self, sock, address)
def server_loop():
sock, address = server_sock.accept()
connection = Connection(sock, address)
_CONNECTIONS.append(connection)
sock.close()
上面把所有建立的连接都放在全局变量 _CONNECTIONS 里, 如果在关闭的时候不从这个列表 里取出(减少引用)则 connection 对象就不会被回收, 则每建立一次连接就会有个连接对象和连接 对象引用的对象不会被回收.
如果把对象放在一个类属性里也是一样的, 因为类对象在程序一开始就分配, 并在程序退出时才被回收.
解决办法就是在退出时从列表(或其他对象)里解除对对象的引用(删除)
_CONNECTIONS = []
class Connection(object):
def __init__(self, sock, address)
def server_loop():
sock, address = server_sock.accept()
connection = Connection(sock, address)
_CONNECTIONS.append(connection)
sock.close()
_CONNECTIONS.remove(connection) # XXX
有时候我们为对象分配一个实例属性时需要将自己本身赋值给实例属性, 作为实例属性的实例属性, 说着很拗口, 看一下代码:
class ConnectionHandler(object):
def __init__(self, connection):
self._conn = connection
class Connection(object):
def __init__(self, sock, address)
self._conn_handler = ConnectionHandler(self) # XXX
上面的代码就会产生交叉引用, 交叉引用会让解释器困惑, 从而之后只能靠2代和3代回收, 这个过程可能会很慢.
解决这种问题的方法就是使用 弱引用
import weakref
class ConnectionHandler(object):
def __init__(self, connection):
self._conn = connection
class Connection(object):
def __init__(self, sock, address)
self._conn_handler = ConnectionHandler(weakref.proxy(self)) # XXX
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具python 释放内存-学网
python 释放内存
状态:1个回答日期:; 包含对象的集合对象被销毁。例如 这些操作都可能使对象变成垃圾回收对象,由垃圾收集器负责收集,当然垃圾收集器也负责处理循环引用对象。 要立即释放,可以使用...状态:1个回答日期:python 怎么在循环中释放内存 #include&stdio.h& main() { char st[15]; printf(&input string:\n&); gets(st); puts(st); } 可以看出当输入的字符串中含有空格时,输...状态:1个回答日期: 我觉得可能是因为你的py文件在第一次启动后,已经编译成pyc文件了,再次启动的时候都是加载pyc,省去了编译的阶段,所以速度很快。 你可以试着把程序目录下的所有pyc或者...状态:1个回答日期: 建立一个全局字典或列表,然后在函数中把不想被回收的对象加入前面的字典(或列表)状态:1个回答日期:原理:python中任何变量都是对象,所以参数只支持引用传递方式。即通过名字绑定的机制,把实际参数的值和形式参数的名称绑定在一起,形式参数和实际参数指向内存中的同一个...状态:1个回答日期:从后面print b能正常输出就可以看出这一点。 python的内存释放采用的是引用计数机制,也就是当一个对象没有任何引用它的变量了,那么它就会自动被释放,无需人工干预。 ...状态:1个回答日期:内存池机制 Python的内存机制以金字塔行,-1,-2层主要有操作系统进行操作, 第0层是C中的malloc,free等内存分配和释放函数进行操作; 第1层和第2层是内存池,有Python的接...状态:1个回答日期:控制内存和 内存便宜没有关系! 内存控制好不 再大内存 也没用. Python 属于脚本语言. 在内存管理方面对 开发者来说非常不明显. 分配出来的 内存 用完尽量释放. 尽量不要把所...状态:1个回答日期:这些中间字符串最终也不回占用多少内存,因为内存占用基本上等同于这些html问价大小之和。 测量过程中有个棘手的问题就是python的内存分配器并不会释放它请求的内存,所...状态:1个回答日期:初始化 --& 使用 --&清理 "在c++的环境中如果初始化了两个类的实例,那么它们是相互影响的(由于全局变量的原因),当然如果开两个进程分别跑是没啥问题。在包成python的...
与【 python 释放内存】相关信息:&&&&&&&&&&&&&&&&&&
用户还关注
12345678910
大类导航: |下次自动登录
现在的位置:
& 综合 & 正文
python扩展——引用计数与内存泄露
转载请注明出处:
Python往往包含大量的内存分配和释放,同样需要避免内存泄漏(对于分配的内存忘记释放)和野指针(读写没有分配的内存区域)。他选择的方法就是 引用计数 。其原理比较简单:每个对象都包含一个计数器,计数器的增减与引用的增减直接相关,当引用计数为0时,表示对象已经没有存在的意义,可以删除了。在pyhton扩展中,C/C++语言来操作python对象的引用计数是一个非常有趣也非常容易出现错误的事情。对于拥有的引用,在不再需要时负责调用 Py_DECREF() 来减少引用计数。忘记减少拥有的引用计数会导致内存泄漏,忘记增加拥有的引用计数可能会导致解释器崩溃,那什么时候需要增减引用计数呢?
拥有权规则
任何人都无法拥有一个对象的所有权,但是可以拥有它的引用。
一个对象的引用无论何时传入或传出一个函数,它都是函数接口规范的一部分,而与所有权被转让与否无关。
大多数返回一个对象引用的函数通过引用转让所有权。尤其是那些功能就是创建新对象的函数,例如PyInt_FromLong()和Py_BuildValue(),会转让所有权给接收者。即使对象实际是不是新创建的,你接收到的仍然是对象的一个新的引用。例如:PyInt_FromLong()维护了常用值的一个缓存,能返回已缓存对象。
需要说明的另外一个概念叫做“借用”对象,顾名思义,借用的对象不需要对它的引用计数加1,所以更不能调用 Py_DECREF() 来减少引用计数。借用的优点是你无需管理引用计数,缺点是可能被野指针搞的头晕,因为你并不能保证借用的这个对象在使用时是不是已经被释放了。PyTuple_GetItem()、PyList_GetItem()、PyDict_GetItem()、和PyDict_-GetItemString()都是返回你从元组、列表或字典借得的引用。
如果一个对象引用被传入另一个函数,一般而言,是函数从你那借用引用——如果函数需要存储引用的话,它要使用Py_INCREF()以成一个独立的所有者。对这一规则,有两个重要的例外:PyTuple_SetItem()和PyList_SetItem()。这两个函数接管传给它们的子项的所有权——即使这些子项失效了!(PyDict_SetItem()那类函数不接管所有权)
当一个C函数在Python中被调用,它从调用者那里借用自已参数的引用。调用者拥有对象的一个引用,所以“借引用”的寿命在返回值退出之前都有保证。仅当这样的“借引用”要被存储或传递时,才要通过调用Py_INCREF()来转换成“拥有引用”。
在Python调用的C函数返回的对象引用必须是“拥有引用”——所有权由函数转让给了它的调用者
常见的一些错误
明显的引用错误
PyObject*_list = PyList_New( 0 );
PyObject*_list1 = PyList_New( 0 );
由于_list1被创建后,既没有被释放(调用Py_DECREF())也没有返回(return转让所有权),所以导致内存泄露。
PyList_Append()
(这个函数说多了都是泪,被他折腾了半天才查到内存泄露的原因。)
一些情况下,扩展函数需要向python返回一个list,于是会有这种写法:
Intvar = …;
PyList_Append(_list,PyInt_FromLong(var);
看上去并没什么毛病,但是追查一番发现问题出现在PyList_Append身上,他会对第二个参数的引用计数加1,在这个例子中PyInt_FromLong(var)返回一个对象,它的引用是1,PyList_Append把这个对象加入到list后,引用计数为2。之后将_list拥有权转交给python调用方。后面可想而知了,调用方在释放这个List的时候只会对计数减一,也就是说该对象计数永远无法到0(也就意味着内存泄露了)。
解决的办法有两个:
PyObject*_list = PyList_New( 0 );
Int var= …;PyObject * tmp = PyInt_FromLong(var);PyList_Append(_list,tmp);Py_DECREF(jpo);…
PyObject*_list = PyList_New( CNT );
Int var= …;
PyList_SetItem(_list,0, PyInt_FromLong(var));
其中CNT表示指定list的长度,然后依次去对每一个下标元素赋值,而不是再采用APPEND的方法。至于为何PyList_SetItem可以解决这个问题,可以参加“拥有权规则哪里的介绍”
等待大家的补充^_^。
&&&&推荐文章:
【上篇】【下篇】}

我要回帖

更多关于 win10内存泄露解决 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信