使用Python管理内存从OODB中读取不同大小的对象

Aar*_*all 7 python memory garbage-collection

我正在从面向对象的数据库中读取一组对象(像sqlite3表或数据帧这样的表),其中大部分都足够小,以至于Python垃圾收集器可以无故障地处理.但是,当它们的尺寸变大(小于10 MB)时,GC似乎无法跟上.

psuedocode看起来像这样:

walk = walkgenerator('/path')
objs = objgenerator(walk)
with db.transaction(bundle=True, maxSize=10000, maxParts=10): 
    oldobj = None
    oldtable = None
    for obj in objs:
        currenttable = obj.table
        if oldtable and oldtable in currenttable:
            db.delete(oldobj.path)
        del oldtable
        oldtable = currenttable
        del oldobj
        oldobj = obj
        if not count % 100:
            gc.collect()
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种优雅的方式来管理内存,同时允许Python尽可能地处理它.

也许令人尴尬的是,我尝试使用del来帮助清理引用计数.

我在for循环中尝试了不同模数的gc.collect():

  • 100(没有区别),
  • 1(减慢循环很多,我仍然会得到某种类型的内存错误),
  • 3(循环仍然很慢,但内存最终仍会爆炸)

建议表示赞赏!

特别是,如果你能给我工具来协助内省.我在这里使用过Windows任务管理器,它似乎或多或少地随机引发内存泄漏.我尽可能地限制交易规模,这似乎有点帮助.

Tim*_*ers 5

这里没有足够的信息说,但我不得不说的不适合评论所以我会在这里发布;-)

首先,最重要的是,在CPython中,垃圾收集主要基于引用计数. gc.collect()不会为你做任何事情(除了刻录时间),除非参与周期中涉及垃圾对象(A可以通过跟随可传递的指针链从自身到达一个对象A).您在显示的代码中没有创建引用循环,但可能是数据库层.

那么,在你运行之后gc.collect(),内存使用是否会完全消失?如果没有,运行它是没有意义的.

我预计数据库层最有可能持有对超过必要时间的对象的引用,但是挖掘它需要深入研究如何实现数据库层的确切细节.

获取线索的一种方法是打印sys.getrefcount()应用于各种大型对象的结果:

>>> import sys
>>> bigobj = [1] * 1000000
>>> sys.getrefcount(bigobj)
2
Run Code Online (Sandbox Code Playgroud)

由于文档说,结果是一般1大于你可能希望的,因为引用计数getrefcount()的说法,只是因为它是临时加1 是被(临时)作为参数.

因此,如果您看到refcount大于2,del则不会释放该对象.

获得线索的另一种方法是将对象传递给gc.get_referrers().返回一个直接引用参数的对象列表(假设引用者参与Python的循环gc).

顺便说一句,你需要更清楚你的意思是"似乎没有工作"和"最终爆炸".无法猜测.究竟出了什么问题?例如,被MemoryError提出了吗?别的什么?Traeback经常会产生一个有用的线索世界.