首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法理解python的gc.garbage (用于跟踪内存泄漏)

无法理解python的gc.garbage (用于跟踪内存泄漏)
EN

Stack Overflow用户
提问于 2013-06-04 06:55:49
回答 1查看 2.2K关注 0票数 7

从稳步增长的内存使用量来看,我的一个python应用程序似乎泄漏了内存。我的假设是一个循环引用某处,尽管尽最大努力避免这一点。为了隔离这个问题,我正在研究如何手动检查无法到达的项,这是一个纯粹用于调试的工具。

gc模块似乎能够进行必要的跟踪,我尝试了下面的代码,该代码旨在编译自上次调用以来形成的不可实现项的列表。第一个调用只设置一个基本检查点,不会识别无法到达的项。

代码语言:javascript
复制
def unreachable():
  # first time setup
  import gc
  gc.set_threshold( 0 ) # only manual sweeps
  gc.set_debug( gc.DEBUG_SAVEALL ) # keep unreachable items as garbage
  gc.enable() # start gc if not yet running (is this necessary?)
  # operation
  if gc.collect() == 0:
    return 'no unreachable items'
  s = 'unreachable items:\n ' \
    + '\n '.join( '[%d] %s' % item for item in enumerate( gc.garbage ) )
  _deep_purge_list( gc.garbage ) # remove unreachable items
  return s # return unreachable items as text

在这里,_deep_purge_list的目标是手动中断循环和删除对象。下面的实现处理一些常见的情况,但并不接近水密。我的第一个问题与此有关,请看。

代码语言:javascript
复制
def _deep_purge_list( garbage ):
  for item in garbage:
    if isinstance( item, dict ):
      item.clear()
    if isinstance( item, list ):
      del item[:]
    try:
      item.__dict__.clear()
    except:
      pass
  del garbage[:]

基于非常有限的测试,设置似乎运行正常。以下循环引用正确地报告了一次:

代码语言:javascript
复制
class A( object ):
  def __init__( self ):
    self.ref = self

print unreachable()
# no unreachable items

A()

print unreachable()
# unreachable items:
#  [0] <__main__.A object at 0xb74579ac>
#  [1] {'ref': <__main__.A object at 0xb74579ac>}

print unreachable()
# no unreachable items

然而,有以下一些奇怪的事情发生了:

代码语言:javascript
复制
print unreachable()
# no unreachable items

import numpy

print unreachable()
# unreachable items:
#  [0] (<type '_ctypes.Array'>,)
#  [1] {'__module__': 'numpy.ctypeslib', '__dict__': <attribute '__dict__' of 'c_long_Array_1' objects>, '__weakref__': <attribute '__weakref__' of 'c_long_Array_1' objects>, '_length_': 1, '_type_': <class 'ctypes.c_long'>, '__doc__': None}
#  [2] <class 'numpy.ctypeslib.c_long_Array_1'>
#  [3] <attribute '__dict__' of 'c_long_Array_1' objects>
#  [4] <attribute '__weakref__' of 'c_long_Array_1' objects>
#  [5] (<class 'numpy.ctypeslib.c_long_Array_1'>, <type '_ctypes.Array'>, <type '_ctypes._CData'>, <type 'object'>)

print unreachable()
# unreachable items:
#  [0] (<type '_ctypes.Array'>,)
#  [1] {}
#  [2] <class 'c_long_Array_1'>
#  [3] (<class 'c_long_Array_1'>, <type '_ctypes.Array'>, <type '_ctypes._CData'>, <type 'object'>)

重复调用不断返回最后的结果。当在导入之后第一次调用不可访问性时,不会出现此问题。但是,在这一点上,我没有理由相信这个问题是特定于numpy的;我猜想它暴露了我的方法中的一个缺陷。

我的问题:

  1. 是否有更好的方法来删除gc.garbage中的项?理想情况下,是否有办法让gc删除它们,就像它应该(应该)那样?已经没有DEBUG_SAVEALL了吗?
  2. 有人能解释numpy导入的问题,并/或提出解决方法吗?

事后思考:

以下代码的执行情况似乎与预期的接近:

代码语言:javascript
复制
def unreachable():
  import gc
  gc.set_threshold( 0 )
  gc.set_debug( gc.DEBUG_LEAK )
  gc.enable()
  print 'collecting {{{'
  gc.collect()
  print '}}} done'

但是,对于调试,我更喜欢富字符串表示形式,而不是gc提供的类型/id。此外,我想了解我的前一种方法的缺陷,并了解一些关于gc模块的内容。

感谢你的帮助,

格特扬

更新06/05:

我遇到这样一种情况,即第一个实现没有报告任何不可访问的项,除非在此之前调用了局部变量()(丢弃返回值)。不了解这如何可能影响gc的对象跟踪,这使我更加困惑。我不知道建立一个证明这个问题的小例子有多容易,但如果需要的话,我可以试一试。

EN

回答 1

Stack Overflow用户

发布于 2013-06-12 18:05:09

上一次我有这样的需求时,我最终使用了 module,效果很好。它提供的信息比直接从 module获得的信息要准确得多。不幸的是,我手头没有任何代码来说明它的用法。

它掉下来的一个地方是由调用的任何C代码库分配的内存。例如,如果一个项目使用PIL,由于没有正确释放由C数据支持的python对象,所以很容易泄漏内存。C支持的模块依赖于如何正确关闭这些对象。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16911559

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档