Python“内存泄漏”当使用线程和 sqlite3 时

发布于 2025-01-10 08:28:47 字数 3874 浏览 0 评论 0原文

我在一个项目中使用 sqlite3 和线程,它给我带来了很多问题。在更好地了解 sqlite3 后,我设法解决了所有这些问题,但我还没有解决内存泄漏。我不知道是否是线程或 sqlite3 或两者导致它。我认为这是两者的结合。我终于成功创建了一个最小的示例来向您展示:

import sqlite3
import threading
import random
import gc
import time

from collections import Counter
import linecache
import os
import tracemalloc

def display_top(snapshot, key_type='lineno', limit=10):
    snapshot = snapshot.filter_traces((
        tracemalloc.Filter(False, "<frozen importlib._bootstrap>"),
        tracemalloc.Filter(False, "<unknown>"),
    ))
    top_stats = snapshot.statistics(key_type)

    print("Top %s lines" % limit)
    for index, stat in enumerate(top_stats[:limit], 1):
        frame = stat.traceback[0]
        # replace "/path/to/module/file.py" with "module/file.py"
        filename = os.sep.join(frame.filename.split(os.sep)[-2:])
        print("#%s: %s:%s: %.1f KiB"
              % (index, filename, frame.lineno, stat.size / 1024))
        line = linecache.getline(frame.filename, frame.lineno).strip()
        if line:
            print('    %s' % line)

    other = top_stats[limit:]
    if other:
        size = sum(stat.size for stat in other)
        print("%s other: %.1f KiB" % (len(other), size / 1024))
    total = sum(stat.size for stat in top_stats)
    print("Total allocated size: %.1f KiB" % (total / 1024))

connection = sqlite3.connect("testdatabase.db", check_same_thread=False)

cursor = connection.cursor()
cursor.execute("DELETE FROM test_table;",);

# This has to be enabled first time running to create the table
# cursor.execute("CREATE TABLE test_table(val1 TEXT, val2 TEXT, val3 TEXT, val4 TEXT, val5 TEXT)")

critical_lock_sqlite = threading.Lock()

def mem_tester(value1,value2,value3,value4,value5):
    try:
        critical_lock_sqlite.acquire(True)
        cursor = connection.cursor()
        if cursor.execute("SELECT val2, val3 FROM test_table WHERE val2=? AND val3=?",
                          (value2, value3)).fetchone():
            del value1, value2, value3, value4, value5
            state_int = 0
        elif not cursor.execute("SELECT val2, val3 FROM test_table WHERE val2=? OR val3=?",
                                (value2, value3)).fetchone():
            state_int = 2
            cursor.execute("INSERT INTO test_table VALUES (?, ?, ?, ?, ?)",
                           (value1, value2, value3, value4, value5))
            connection.commit()
        elif cursor.execute("SELECT val3 FROM test_table WHERE val3=?", (value3,)).fetchone():
            state_int = 1
            cursor.execute("UPDATE test_table SET val2=? WHERE val3=?", (value2, value3))
        elif not cursor.execute("SELECT val2, val3 FROM test_table WHERE val2=? AND val3=?",
                                (value2, value3)).fetchone():
            state_int = 2
            cursor.execute("INSERT INTO test_table VALUES (?, ?, ?, ?, ?)",
                           (value1, value2, value3, value4, value5))
            connection.commit()
        # Unexpected Occurrance
        else:
            state_int = 2
            cursor.execute("INSERT INTO test_table VALUES (?, ?, ?, ?, ?)",
                           (value1, value2, value3, value4, value5))
            connection.commit()
        cursor.close()
        del cursor
    finally:
        critical_lock_sqlite.release()
if __name__ == '__main__':
    tracemalloc.start()
    for i in range(1, 10000):
        threading.Thread(target=mem_tester, args=("test",random.randint(1, 999),''.join(random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890") for _ in range(8)),"random","random")).start()
    gc.collect()
    time.sleep(5)
snapshot = tracemalloc.take_snapshot()
display_top(snapshot)

我很难在这里找到问题。内存不断增加,如果我删除 critical_lock_sqlite,它不会增加那么多,但随后我将出现一百万个错误,因为我不允许在不同线程中同时运行命令。有谁能帮我解决这个案子吗?
请注意,此脚本还将显示使用最多内存的位置。在这种情况下,它主要表明正在使用线程。
谢谢你!

I'm using sqlite3 and threading for a project I have and It's brought me a lot of problems. I managed to solve all of them after getting a better understanding of sqlite3 but I have not managed to solve a memory leak. I have no idea if it's the threading or sqlite3 or both causing it. I think it's a combination of both. I have finally managed to create a minimal example to show you:

import sqlite3
import threading
import random
import gc
import time

from collections import Counter
import linecache
import os
import tracemalloc

def display_top(snapshot, key_type='lineno', limit=10):
    snapshot = snapshot.filter_traces((
        tracemalloc.Filter(False, "<frozen importlib._bootstrap>"),
        tracemalloc.Filter(False, "<unknown>"),
    ))
    top_stats = snapshot.statistics(key_type)

    print("Top %s lines" % limit)
    for index, stat in enumerate(top_stats[:limit], 1):
        frame = stat.traceback[0]
        # replace "/path/to/module/file.py" with "module/file.py"
        filename = os.sep.join(frame.filename.split(os.sep)[-2:])
        print("#%s: %s:%s: %.1f KiB"
              % (index, filename, frame.lineno, stat.size / 1024))
        line = linecache.getline(frame.filename, frame.lineno).strip()
        if line:
            print('    %s' % line)

    other = top_stats[limit:]
    if other:
        size = sum(stat.size for stat in other)
        print("%s other: %.1f KiB" % (len(other), size / 1024))
    total = sum(stat.size for stat in top_stats)
    print("Total allocated size: %.1f KiB" % (total / 1024))

connection = sqlite3.connect("testdatabase.db", check_same_thread=False)

cursor = connection.cursor()
cursor.execute("DELETE FROM test_table;",);

# This has to be enabled first time running to create the table
# cursor.execute("CREATE TABLE test_table(val1 TEXT, val2 TEXT, val3 TEXT, val4 TEXT, val5 TEXT)")

critical_lock_sqlite = threading.Lock()

def mem_tester(value1,value2,value3,value4,value5):
    try:
        critical_lock_sqlite.acquire(True)
        cursor = connection.cursor()
        if cursor.execute("SELECT val2, val3 FROM test_table WHERE val2=? AND val3=?",
                          (value2, value3)).fetchone():
            del value1, value2, value3, value4, value5
            state_int = 0
        elif not cursor.execute("SELECT val2, val3 FROM test_table WHERE val2=? OR val3=?",
                                (value2, value3)).fetchone():
            state_int = 2
            cursor.execute("INSERT INTO test_table VALUES (?, ?, ?, ?, ?)",
                           (value1, value2, value3, value4, value5))
            connection.commit()
        elif cursor.execute("SELECT val3 FROM test_table WHERE val3=?", (value3,)).fetchone():
            state_int = 1
            cursor.execute("UPDATE test_table SET val2=? WHERE val3=?", (value2, value3))
        elif not cursor.execute("SELECT val2, val3 FROM test_table WHERE val2=? AND val3=?",
                                (value2, value3)).fetchone():
            state_int = 2
            cursor.execute("INSERT INTO test_table VALUES (?, ?, ?, ?, ?)",
                           (value1, value2, value3, value4, value5))
            connection.commit()
        # Unexpected Occurrance
        else:
            state_int = 2
            cursor.execute("INSERT INTO test_table VALUES (?, ?, ?, ?, ?)",
                           (value1, value2, value3, value4, value5))
            connection.commit()
        cursor.close()
        del cursor
    finally:
        critical_lock_sqlite.release()
if __name__ == '__main__':
    tracemalloc.start()
    for i in range(1, 10000):
        threading.Thread(target=mem_tester, args=("test",random.randint(1, 999),''.join(random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890") for _ in range(8)),"random","random")).start()
    gc.collect()
    time.sleep(5)
snapshot = tracemalloc.take_snapshot()
display_top(snapshot)

I'm having a hard time finding the problem here. The memory keeps going up and if I remove the critical_lock_sqlite, it won't go up as much but then I will have a million errors because I am not allowed to run the commands at the same time in different threads. Is anyone able to help me with this case?
Note that this script will also show where the most memory is used. In this case it shows mostly that threading is using.
Thank you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文