【问题标题】:Django memory leakDjango内存泄漏
【发布时间】:2014-07-11 07:37:40
【问题描述】:

我正在开发一个 python 应用程序,它使用 Django ORM 作为独立的来管理数据库,但我面临着一个很大的内存问题。我发现导致此问题的部分是:

ports_list_save = []
    for host in results['hosts']:
        for protocol in results['hosts'][host]['protocols']:
            for port in results['hosts'][host]['protocols'][protocol]:
                current_port = history.Port(number=int(port), 
                                            protocol=protocol, 
                                            state=results['hosts'][host]['protocols'][protocol][port]['state'], 
                                            service='', 
                                            version='', 
                                            address=history.Ip.objects.get(scan=self.scan, address=host))
                ports_list_save.append(current_port)
    history.Port.objects.bulk_create(ports_list_save)

这部分在 154 个主机和每台主机 150 个端口 (23000) 对象上运行良好,但现在我尝试使用 1000 个端口和我的计算机内存每次都会爆炸。

还有一件事,我没有在调试模式下运行Django,所以内存不是来自 django.db.backends.postgresql_psycopg2.base.DatabaseWrapper

【问题讨论】:

  • 我不确定我是否理解问题所在。您已将数据数量增加了约 10 倍,因此您应该预期内存使用量增加约 10 倍。这里发生了一些不寻常的事情吗? IE。是什么让您认为存在内存泄漏?
  • 该进程使用超过 2Go RAM + 1Go SWAP 来处理 100k * 3 个最多 10 个字符的字符串,对我来说听起来太多了。
  • 但是你不是在处理字符串。这些是 Python 对象。每小块数据都占用内存,它们可以使用千字节。看起来不像是内存泄漏。

标签: python django python-3.x


【解决方案1】:

如果您有大量数据,您可能仍需要分块加载和处理,试试这个:

CHUNK_SIZE = 23000
ports_list_save = []
for host in results['hosts']:
    for protocol in results['hosts'][host]['protocols']:
        for port in results['hosts'][host]['protocols'][protocol]:
            current_port = history.Port(number=int(port), 
                                        protocol=protocol, 
                                        state=results['hosts'][host]['protocols'][protocol][port]['state'], 
                                        service='', 
                                        version='', 
                                        address=history.Ip.objects.get(scan=self.scan, address=host))
            ports_list_save.append(current_port)
            if len(ports_list_save) > CHUNK_SIZE:
                history.Port.objects.bulk_create(ports_list_save)
                ports_list_save = []
if ports_list_save:   
    history.Port.objects.bulk_create(ports_list_save)

【讨论】:

  • 工作得很好,谢谢 :)。顺便说一句,我发现了一些有用的东西,它在每个“for host in results['hosts']”循环结束时调用“gc.collect()”。这是一件坏事吗?哪种方式最好?
  • 我不确定。致电gc.collect() 不会有任何伤害,但我不确定您是否从中受益匪浅。我会忽略它,除非你看到显着的改进。
【解决方案2】:

我遇到了同样的问题,最终得到了这个解决方案:

class BulkCreateManager(object):

    model = None
    chunk_size = None
    instances = None

    def __init__(self, model, chunk_size=None, *args):
        self.model = model
        self.chunk_size = chunk_size
        self.instances = []

    def append(self, instance):
        if self.chunk_size and len(self.instances) > self.chunk_size:
            self.create()
            self.instances = []

        self.instances.append(instance)

    def create(self):
        self.model.objects.bulk_create(self.instances)



ports_list_save = BulkCreateManager(history.Port, 23000)
for host in results['hosts']:
    for protocol in results['hosts'][host]['protocols']:
        for port in results['hosts'][host]['protocols'][protocol]:
            current_port = history.Port(number=int(port), 
                                        protocol=protocol, 
                                        state=results['hosts'][host]['protocols'][protocol][port]['state'], 
                                        service='', 
                                        version='', 
                                        address=history.Ip.objects.get(scan=self.scan, address=host))
            ports_list_save.append(current_port)

ports_list_save.create()

【讨论】:

    猜你喜欢
    • 2020-07-13
    • 2014-08-09
    • 1970-01-01
    • 2019-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-06
    • 2013-11-24
    相关资源
    最近更新 更多