Python MySQLdb模块内存泄漏

时间:2014-03-26 10:24:45

标签: python mysql memory-leaks

流行的python mysql模块" MySQLdb"似乎有内存泄漏问题。 这是代码:

conn = MySQLdb.connect(...)
cursor = conn.cursor(cursorclass = MySQLdb.cursors.DictCursor)
sql = "select * from `test`"
cursor.execute(sql)  #leak start
cursor.close()
conn.close()
time.sleep(20)

假设test是一个包含十亿条记录的表。我运行了python代码并执行

ps aux | awk '{print $2, $4, $11}' | grep python

同时,结果是内存使用率增加到47.0%并且永远不会回头,即使我关闭了光标和conn。有什么想法吗?

1 个答案:

答案 0 :(得分:8)

this post中,Fredrik Lundh解释了为什么内存可能无法返回系统,即使它不是内存泄漏。 在底部附近,他解释了为什么(在Python2中)range(50*1024*100)可能消耗大量内存,即使在删除列表后也无法释放。他提到使用xrange是一种避免记忆问题的方法。

同样,使用SSDictCursor代替DictCursor可能是一种避免内存问题的方法。 SSDictCursor导致MySQL服务器在服务器端保留结果集,并且光标将仅在需要时一次一个地从结果集中获取行:

import MySQLdb
import MySQLdb.cursors as cursors
conn = MySQLdb.connect(..., cursorclass=cursors.SSDictCursor) #1
cursor = conn.cursor()
cursor.execute('select * from test')  #2
for row in cursor:                    #3
    print(row)
conn.close()
  1. 请注意连接调用中的cursorclass=cursors.SSDictCursor
  2. 使用DictCursor(或任何非SS游标),此次execute调用会导致MySQLdb 将整个结果集加载到Python对象(例如dicts列表)中。
  3. 使用SSDictCursorMySQLdb一次检索一行。
  4. 因此,如果您不需要一次性保存Python中的整个结果集,这将避免内存构建问题。

    另请注意,使用SSCursorSSDictCursor时,“无法在连接上发出新查询until the entire result set has been fetched.”可以同时使用来自两个不同连接的游标。这对你来说可能不是问题,但需要注意的是。

    您可能还想查看oursql,这是MySQL的替代数据库适配器。 oursql游标是服务器端游标fetch lazily by default