【问题标题】:Memory management in DjangoDjango中的内存管理
【发布时间】:2026-01-14 11:25:02
【问题描述】:

我正在对我的 Django 数据库进行一些分析。我在一个循环中执行了许多查询,其中一些查询可能会返回很大的结果。
因此,过了一会儿,我的 EC2 实例上的整个 8 GB RAM 都被吃掉了,我什至无法再通过 ssh 连接到机器了。
我必须重新启动实例,然后重新开始。

我尝试了这里提到的解决方案:
https://baxeico.wordpress.com/2014/09/30/optimize-django-memory-usage/ 但是queryset_iterator 方法似乎不适用于聚合查询。
我很确定任何单个查询都不能消耗所有 8 GB 的 RAM。因此,这意味着旧的结果不会从内存中删除。

如何在循环迭代结束之前和执行下一个查询之前强制将查询从内存中取出?

这是我的代码:

def get_users_event_distribution(monthYear, event_type=None):
    title = event_type if (event_type) else 'All'

    filename = 'charts/%s_%s_event_dist.png'%(monthYear, title)
    filename = filename.replace(' ', '')

    if os.path.isfile(filename):
        print 'Chart already in file %s'%(filename)
    else:
        users = None
        if event_type:
                users = EVENT.objects.filter(time__month=monthYear.month, time__year=monthYear.year, event_type=event_type).values_list('user').annotate(count=Count('id'))
        else:
                users = EVENT.objects.filter(time__month=monthYear.month, time__year=monthYear.year).values_list('user').annotate(count=Count('id'))

        uc = users.count()
        print 'We have %d users'%(uc)

        print 'Building Count Dictionary'
        count_dict = dict()
        for u in users:
            try:
                count_dict[u[1]] += 1
            except:
                count_dict[u[1]] = 1
            count += 1

        print 'Built the count dictionary with %d keys'%(len(count_dict.keys()))

        fig, ax = plt.subplots(figsize=(20, 20))
        bars = plt.bar(range(len(count_dict)), count_dict.values(),
                       align='edge')
        locs, labels = plt.xticks(range(len(count_dict)), count_dict.keys())
        ax.set_ylabel('# Users')
        ax.set_xlabel('# %s Events' % (title))
        ax.set_title('%s Event Distribution'%(title))
        ax.relim()
        # update ax.viewLim using the new dataLim
        ax.autoscale_view()

        def autolabel(rects):
            """
            Attach a text label above each bar displaying its height
            """
            for rect in rects:
                height = rect.get_height()
                ax.text(rect.get_x() + rect.get_width() / 2., 1.05 * height,
                        '%d' % int(height),
                        ha='center', va='bottom')

        autolabel(bars)
        plt.savefig(filename, bbox_inches='tight', dpi=100)
        print 'saved the distribution chart to %s'%(filename)

def get_users_all_event_distribution(monthYear):
    get_users_event_distribution(monthYear)
    for event_type in [event_type[0] for event_type in EVENT_TYPE]:
        get_users_event_distribution(monthYear, transaction_type)

我在循环中为不同的日期运行get_users_all_event_distribution

【问题讨论】:

  • 没有看到一些代码就无法提供帮助。
  • 先试试显而易见的,在设置中设置DEBUG = False。如果启用调试,django 会缓存很多东西,包括查询。
  • @DanielRoseman 完成
  • @BurhanKhalid 不知道这一点。我会试试的。
  • @BurhanKhalid 好吧,它没有帮助。我注意到它跑得更快了,但内存仍在不断填满。

标签: python django amazon-ec2


【解决方案1】:

通过更多分析,我发现问题出在 matplot 数字中,如此警告中所述:

/usr/local/lib64/python2.7/site-packages/matplotlib/pyplot.py:524: 运行时警告:已打开 20 多个图形。创建的数字 通过pyplot接口(@98​​7654321@)被保留 直到显式关闭并且可能会消耗太多内存。 (控制 此警告,请参阅 rcParam figure.max_open_warning)。
max_open_warning, RuntimeWarning)

我添加了plt.close('all') 行。

【讨论】: