使用Python从OODB'读取不同大小的对象来管理内存;s

使用Python从OODB'读取不同大小的对象来管理内存;s,python,memory,garbage-collection,Python,Memory,Garbage Collection,我正在从一个面向对象的数据库中读取一组对象(如sqlite3表或dataframes表),其中大多数都足够小,Python垃圾收集器可以处理而不会发生意外。然而,当它们变得更大(小于10MB)时,GC似乎无法跟上 伪代码如下所示: walk = walkgenerator('/path') objs = objgenerator(walk) with db.transaction(bundle=True, maxSize=10000, maxParts=10): oldobj = No

我正在从一个面向对象的数据库中读取一组对象(如sqlite3表或dataframes表),其中大多数都足够小,Python垃圾收集器可以处理而不会发生意外。然而,当它们变得更大(小于10MB)时,GC似乎无法跟上

伪代码如下所示:

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()
我正在寻找一种优雅的方法来管理内存,同时尽可能让Python处理它

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

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

  • 100(无差异)
  • 1(循环速度减慢了很多,我仍然会得到某种类型的内存错误)
  • 3(循环仍然很慢,但最终内存仍然会崩溃)
感谢您的建议


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

这里没有足够的信息可以多说,但我要说的内容不适合评论,所以我将在这里发布;-)

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

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

我认为数据库层保存对象引用的时间很可能比需要的时间长,但深入研究这一点需要深入了解数据库层是如何实现的

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

>>> import sys
>>> bigobj = [1] * 1000000
>>> sys.getrefcount(bigobj)
2
正如文档所说,结果通常比您希望的大1,因为
getrefcount()
的参数的refcount临时增加1,这仅仅是因为它被用作(临时)参数

因此,如果看到refcount大于2,
del
将不会释放对象

获取线索的另一种方法是将对象传递给
gc.get\u referers()
。它返回直接引用参数的对象列表(前提是引用方参与Python的循环gc)


顺便说一句,你需要更清楚你所说的“似乎不起作用”和“最终爆炸”是什么意思。猜不到。到底出了什么问题?例如,
MemoryError
是否已引发?还有别的吗?traeback通常会产生大量有用的线索。

我在python中没有做很多内存操作,但是如果您正在寻找低级别的内存控制,请尝试使用ctypes模块