Python MySQLdb 模块内存泄漏

问题描述 投票:0回答:1

流行的 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。有什么想法吗?

python mysql memory-leaks
1个回答
10
投票

这篇文章中,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 对象中(例如字典列表)。
  3. 使用
    SSDictCursor
    MySQLdb
    一次检索一行。

因此,如果您不需要在 Python 中一次性保存整个结果集,这将避免内存累积问题。

另请注意,使用

SSCursor
SSDictCursor
时,“在获取整个结果集之前,无法在连接上发出新查询。”可以同时使用来自两个不同连接的游标。这对您来说可能不是问题,但需要注意。

您可能还想查看

oursql,这是 MySQL 的替代数据库适配器。 oursql

游标是服务器端游标,默认情况下
延迟获取

© www.soinside.com 2019 - 2024. All rights reserved.