2017-07-24 48 views
0

下面的代码泄漏在我的系统存储器:SQLAlchemy的泄漏内存

def test(): 
    for u in users: 
     session.flush() 
     some_list = u.some_list 

users被定义为

users = session.query(User).yield_per(500000)

some_list在用户模型定义为

some_list = relationship("SomeThing", backref="user") 

正如你所看到的,跑步session.flush()不释放使用过的内存。对于这个问题,在循环结束时del some_list也没有。如果我删除some_list = u.some_list行,内存泄漏消失。

编辑:根据要求,这里是相关文件的完整代码。但我认为这不会有多大帮助,因为我只能使用功能test()来重现问题。

from redis import Redis 
from pottery import RedisDict 
import json 

from anime_db import generate_session, User 

redis = Redis.from_url('http://localhost:6379') 
toshokan = RedisDict(redis=redis, key='toshokan') 

session = generate_session(User) 
users = session.query(User).yield_per(5000) 


users = users[200000:] 

def process(): 
    c = 0 
    for u in users: 
     session.flush() 
     if c % 10000 == 0: 
      print('PROCESSED {} USERS'.format(c)) 
     c += 1 
     al_db = u.animelist 
     name = u.name 
     if len(al_db) == 0 or name in toshokan: 
      continue 
     al = [] 
     for a in al_db: 
      al.append((a.anime_id, a.status, a.num_watched, a.score)) 
     toshokan[name] = json.dumps(al) 
     del al_db, name, al 

def test(): 
    c = 0 
    for u in users: 
     session.flush() 
     if c % 1000 == 0: 
      print('something') 
     c += 1 
     name = u.name 
     al_db = u.animelist 

相关的数据库模型被定义为这样的:

class AnimeEntry(Base): 
    __tablename__ = 'list_entries_anime' 

    uid = Column(Integer, Sequence('anime_list_entry_id_seq'), primary_key=True, autoincrement=True) 
    anime_id = Column(Integer, ForeignKey("anime.uid"), nullable=False) 
    user_id = Column(Integer, ForeignKey("users.uid"), nullable=False) 
    status = Column(Integer) 
    num_watched = Column(Integer) 
    score = Column(Integer) 
    added = Column(DateTime(timezone=True), default=func.now()) 

    def __repr__(self): 
     return "<AnimeEntry(uid='%s', title='%s', user='%s')>" % (self.uid, self.anime_id, self.user_id) 

class User(Base): 
    """A user entry.""" 
    __tablename__ = 'users' 

    uid = Column(Integer, Sequence('user_id_seq'), primary_key=True, autoincrement=True) 
    name = Column(String, unique=True) 

    joined = Column(DateTime(timezone=True), default=func.now()) 
    animelist = relationship("AnimeEntry", backref="user") 

编辑:停止循环不会停止内存使用情况,但运行users = []事后做。所以这个问题是相关的session.query(User).yield_per(5000)

+0

为什么你认为'session.flush()'会释放内存?你需要'session.expunge_all()'。 – univerio

+0

我被告知别处flush()会工作;它没。对于这个问题,也没有expunge_all()。 –

+0

你怎么看待你有内存泄漏?你的代码的其余部分是做什么的? – univerio

回答

0

看起来yield_per()在某种程度上导致不合理的内存使用情况。我用下面的代码替换了那段代码:

def page_query(q): 
    offset = 0 
    while True: 
     r = False 
     for elem in q.limit(10000).offset(offset): 
      r = True 
      yield elem 
     offset += 10000 
     if not r: 
      break 

users = page_query(session.query(User)) 

其中的工作方式与预期的一样。我仍然不知道为什么yield_per的行为方式如此,我之前使用过它,它在这种情况下表现得很好。