【问题标题】:Memory leak with large dataset when using mysql-python使用 mysql-python 时存在大型数据集的内存泄漏
【发布时间】:2013-06-14 14:20:57
【问题描述】:

我在使用 MySQLdb API 时遇到了我认为是内存泄漏的问题

Line #    Mem usage    Increment   Line Contents
================================================
     6                             @profile
     7    10.102 MB     0.000 MB   def main():
     8    10.105 MB     0.004 MB       connection = MySQLdb.connect(host="localhost", db="mydb",
     9    11.285 MB     1.180 MB                                    user="notroot", passwd="Admin123", use_unicode=True)
    10    11.285 MB     0.000 MB       cursor = connection.cursor(cursorclass=MySQLdb.cursors.SSCursor)
    11                                 
    12    11.289 MB     0.004 MB       cursor.execute("select * from a big table;")
    13                                 
    14   254.078 MB   242.789 MB       results = [result for result in cursor]
    15   251.672 MB    -2.406 MB       del results
    16   251.672 MB     0.000 MB       return

当使用guppy/hpy 探索堆时,它显示我的大部分内存都被 unicode 对象、整数和日期时间对象占用(很可能是 MySQLdb API 返回的行)。

我在 Ubuntu 12.04 上使用 Python 2.7.3,mysql-python==1.2.4,并使用 memory_profiler 进行了分析。

这可能是http://effbot.org/pyfaq/why-doesnt-python-release-the-memory-when-i-delete-a-large-object.htm 中描述的实习吗?

我是否遗漏了任何悬而未决的参考资料?

编辑:我也关闭了光标和连接,但仍然得到类似的结果。

已解决: 掌心。我正在做一个列表理解,自然地将所有内容都保存在内存中。正确使用迭代器(流式传输到文件或其他内容)时,它具有不错的内存使用率。

Line #    Mem usage    Increment   Line Contents
================================================
    16                             @profile
    17    10.055 MB     0.000 MB   def main():
    18    10.059 MB     0.004 MB       connection = MySQLdb.connect(host="localhost", db="mydb",
    19    11.242 MB     1.184 MB                                    user="notroot", passwd="Admin123", use_unicode=True)
    20    11.242 MB     0.000 MB       cursor = connection.cursor(cursorclass=MySQLdb.cursors.SSCursor)
    21                                 
    22    11.246 MB     0.004 MB       cursor.execute("select * from big table")
    23    11.246 MB     0.000 MB       count = 0
    24    30.887 MB    19.641 MB       for result in cursor:
    25    30.887 MB     0.000 MB           count = count + 1
    26    30.895 MB     0.008 MB       cursor.close()
    27    30.898 MB     0.004 MB       connection.close()
    28    30.898 MB     0.000 MB       return

【问题讨论】:

  • 删除光标会发生什么?关闭连接?这对我来说听起来像是缓存。提示:当一个简单的list(bar) 可以使用时,不要使用[foo for foo in bar]
  • 另外,操作系统不会立即释放内存。内存仍然分配给 Python,以防进程再次需要它,只有在其他地方需要它时才会从进程中删除。仅仅因为 python 释放内存确实意味着操作系统会立即回收它。
  • 循环运行最终会吃掉所有内存吗?
  • @AndreiComan 无法保证内存会返回给操作系统,因此 top/ps/memory_profiler 和其他工具会显示进程的内存使用量减少。相反,分配的地址空间保留在进程中的“池”中。这通常没有问题,因为这是虚拟内存,操作系统最终会通过换出未使用的物理内存来解决问题。这也不是特定于 python。如果在执行类似操作时内存不断增加,则可能表明存在问题虽然
  • 很高兴您找到了解决问题的方法!你能把它写成一个实际的答案,这样它就不再被标记为打开了吗?

标签: python mysql


【解决方案1】:

已由 OP 解决。他的原始代码包含该行

results = [result for result in cursor]

此列表解析将整个结果存储在内存中,而不是根据需要从服务器流式传输。 OP用一个简单的替换它

for result in cursor:
    ...

并且看到他的内存使用恢复正常。

【讨论】:

    猜你喜欢
    • 2012-01-14
    • 1970-01-01
    • 2016-06-11
    • 1970-01-01
    • 2021-11-23
    • 2016-03-16
    • 1970-01-01
    • 2012-12-02
    • 2011-12-13
    相关资源
    最近更新 更多