已解决不是问题,原因是:
def __del__(self):
print "deleted!"
在模型类中。一旦我从模型类中删除它,我就无法尝试使用内存的任何问题。
我有一些模型,我正在使用ad-hoc会话/引擎,这工作正常,但是当我想在数据库/会话上下文之外创建这些对象时,似乎SQLAlchemy工具保留了对对象,它们永远不会被删除。
我想要做的是创建一个类似“普通”Python对象的模型对象,并且永远不要将它添加到任何会话/数据库中(但在其他上下文中我需要将它添加到数据库中)。这是错的吗?
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
编辑我做了一些额外的测试,如果对象永远不会被提交到会话中(例如回滚),那么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()
答案 0 :(得分:3)
使用__del__()
可create memory leaks,因为如果某个对象成为循环的主题,则循环GC无法访问该对象。在这个测试中就是这种情况,因为SQLAlchemy对象检测在对象是"脏"的情况下创建了从对象到自身的循环,即具有要刷新到数据库的待定属性,所以您可以向Session添加一个脏对象,然后丢失对它的所有引用,并且仍然会刷新更改。这个"参考标记"一旦对象被标记为干净(即刷新),就会被删除。
对于SQLAlchemy 0.8.1我improved this behavior:一个是不再为"待定"创建此参考周期或"分离"对象,即与会话无关的对象。相反,当对象附加到.modified标志的Session时检查该对象,并且引用标记仅在该点处关联(并且当对象变得干净时被删除,如已经存在的情况)。如果对象与会话分离,则无条件地删除标记,即使对象仍有更改 - .modified标志保持为true。
此外,我在第一次映射类并检测到具有__del__()
方法时添加了警告。 Python对象很容易有循环,在SQLAlchemy的情况下,在带有backref的类上放置relationship()
的模式也会产生创建引用循环的效果,所以即使使用这里的状态管理改进,使用__del__()
是一个坏主意。