gpt4 book ai didi

未提交检测对象(例如回滚)时 SQLAlchemy 内存泄漏

转载 作者:行者123 更新时间:2023-12-01 23:13:17 24 4
gpt4 key购买 nike

已解决 不是问题,是由以下原因引起的:

def __del__(self):
print "deleted!"

在模型类中。一旦我将它从模型类中删除,我就无法试验任何内存使用问题。

我有一些模型与临时 session /引擎一起使用,这工作正常,但是当我想在数据库/ session 上下文之外创建这些对象时,SQLAlchemy 工具似乎保留了对对象,它们永远不会被删除。

我想做的是创建一个像“普通”Python 对象一样的模型对象,并且从不将它添加到任何 session /数据库中(但在其他情况下我需要将它添加到数据库中)。这是错误的吗?

import gc
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, String

base = declarative_base()

class SomeObject(base):
__tablename__ = "SomeObject"

instrumented_name = Column('name', String(55), primary_key=True)
uninstrumented_name = None

def __del__(self):
print "deleted!"

obj1 = SomeObject()
obj1.uninstrumented_name = "foo"
obj1 = None

#obj1 is properly deleted

obj2 = SomeObject()
obj2.instrumented_name = "bar"
obj2 = None
gc.collect()

#obj2 never deleted

编辑 我做了一些额外的测试,如果对象从未提交到 session 中(例如回滚),SQLAlchemy 似乎会导致内存泄漏

是否有一种方法可以强制 SQLAlchemy 释放它对检测对象的引用?

import gc
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, create_engine

Base = declarative_base()

class MemoryMonster(Base):
__tablename__ = "MemoryMonster"

_id = Column('id', Integer(), primary_key=True)
_name = Column('name', String(55))

def __init__(self):
self._name = "some monster name"
self._eat_some_ram = ' ' * 1048576

def __del__(self):
print "deleted!"


engine = create_engine("sqlite:///:memory:")
session_factory = sessionmaker(engine)
Session = scoped_session(session_factory)

Base.metadata.create_all(engine)


def create_and_commit():
session = Session()
for _ in range(100):
session.add(MemoryMonster())
session.commit()
Session.remove()
gc.collect()


def create_and_rollback():
session = Session()
for _ in range(100):
monster = MemoryMonster()
session.add(monster)
session.expunge(monster)
session.rollback()
Session.remove()
gc.collect()


def create_do_not_include_in_session():
session = Session()
for _ in range(100):
monster = MemoryMonster()
session.rollback()
Session.remove()
gc.collect()


# Scenario 1 - Objects included in the session and commited
# No memory leak
create_and_commit()

# Scenario 2 - Objects included in the session and rollbacked
# Memory leak
create_and_rollback()

# Scenario 3 - Objects are not not included in the session
# Memory leak
create_do_not_include_in_session()

最佳答案

使用 __del__() 可以 create memory leaks ,因为如果一个对象成为循环的主题,那么循环 GC 将无法访问它。在这个测试中就是这种情况,因为在对象“脏”的情况下,SQLAlchemy 对象工具会创建一个从对象到自身的循环,也就是说,有待处理的属性要刷新到数据库中,这样你就可以添加一个将脏对象添加到 Session,然后丢失对它的所有引用,更改仍将被刷新。一旦对象被标记为干净(即冲洗),这个“引用标记”就会被删除。

对于 SQLAlchemy 0.8.1,我有 improved this behavior :一个是不再为“挂起”或“分离”对象(即与 session 无关的对象)创建此引用循环。相反,当对象附加到 .modified 标志的 Session 时,会检查该对象,并且仅在该点关联引用标记(并且在对象变得干净时被删除,就像已经发生的情况一样)。如果对象从 session 中分离,标记将被无条件删除,即使对象仍然有更改——.modified 标志保持为真。

此外,当一个类首次被映射并检测为具有 __del__() 方法时,我添加了一个警告。 Python 对象很容易有循环,在 SQLAlchemy 的情况下,将 relationship() 放在带有 backref 的类上的模式也会产生引用循环的效果,所以即使随着此处状态管理的改进,使用 __del__() 不是一个好主意。

关于未提交检测对象(例如回滚)时 SQLAlchemy 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16091891/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com