加载字典对象导致内存尖峰



我有一个字典对象,其中约有60,000个键,我可以在Django视图中访问并访问。该视图提供了基本的搜索功能,我在词典中寻找搜索词,例如:

projects_map = cache.get('projects_map')
projects_map.get('search term')

但是,只需抓取缓存的对象(在第1行中)会导致服务器上的内存使用中的一个巨大尖峰 - 有时超过100mbs-即使返回值并呈现了模板,也不会发布内存。/p>

我如何防止记忆像这样升起?另外,在抓住该值后,我尝试明确删除对象,但即使不是释放内存尖峰。

任何帮助都非常感谢。

更新:解决方案我最终实现

我决定实现自己的索引表,其中我存储了密钥及其腌制价值。现在,我使用的是:

,而不是在字典上使用 get()

ProjectsIndex.objects.get(index_key=<search term>)

并取消挑选价值。由于我不再将巨型对象加载到内存中,因此这似乎会照顾记忆问题。它在页面上添加了另一个小查询,但仅此而已。似乎是完美的解决方案...目前。

..如何使用一些适当的服务来缓存,例如redis或memcached而不是将巨大对象加载到存储器侧面?这样,如果字典增长了。

,您甚至可以在额外的机器上进行扩展

无论如何,100MB内存包含所有数据 哈希索引 MISC。高架;前几天,我注意到自己在退出Python过程之前很多次不会被交易(我从Python解释器中填写了几次内存,加载了一个巨大的JSON对象.. :));如果有人对此有解决方案,那将很有趣。

更新:带有很少内存的缓存

仅使用512MB RAM的选项是:

  • 使用redis,在这里查看http://redis.io/topics/memory-optimization(但我怀疑512MB还不够,甚至优化)
  • 使用单独的计算机(或一个群集,因为备忘录和redis支持sharding)使用更多的RAM来保持缓存
  • 使用数据库缓存后端,因为它保存在磁盘上的所有内容
  • 使用文件系统缓存(尽管我看不到比数据库缓存更喜欢此的点)

,在后两种情况下,尝试将您的对象分开,以免立即从缓存中检索物体的兆字节。

更新:懒惰跨越多个缓存键

您可以用这样的东西替换缓存的dict;这样,您可以继续像普通词典一样继续对其进行处理,但是只有在您真正需要它的情况下,数据才会从缓存中加载。

from django.core.cache import cache
from UserDict import DictMixin
class LazyCachedDict(DictMixin):
    def __init__(self, key_prefix):
        self.key_prefix = key_prefix
    def __getitem__(self, name):
        return cache.get('%s:%s' % (self.key_prefix, name))
    def __setitem__(self, name, value):
        return cache.set('%s:%s' % (self.key_prefix, name), value)
    def __delitem__(self, name):
        return cache.delete('%s:%s' % (self.key_prefix, name))
    def has_key(self, name):
        return cache.has_key(name)
    def keys():
        ## Just fill the gap, as the cache object doesn't provide
        ## a method to list cache keys..
        return []

然后替换以下:

projects_map = cache.get('projects_map')
projects_map.get('search term')

with:

projects_map = LazyCachedDict('projects_map')
projects_map.get('search term')

我不知道Windows是如何工作的,但是在Linux中,进程实际上无法将内存返回到系统。这是因为一个过程地址空间是连续的,而增加内存的唯一可用系统调用是brk(),它只是增加了一个指针,该指针标记了一个可用的过程。

应用程序使用(malloc等)的所有分配器均在用户空间中定义为库。它们在字节块级别上操作,并使用brk()仅增加内部存储器池。在运行的应用程序中,此内存池用请求的块混乱。将内存返回系统的唯一可能性是,当池的最后一部分没有使用块时(非常不可能,这将是显着尺寸的,因为即使简单的应用程序也分配并分配了数千个对象)。

>

因此,由记忆尖峰引起的膨胀将一直持续到最后。解决方案:

  • 即使是由临时对象引起的,避免使用内存用法来避免尖峰(例如:通过行进行文件,而不是一次读取整个内容)
  • 将缓存放在另一个过程中(如第一个答案中所建议的备忘录)
  • 使用序列化词典(gdbm)或其他从Process'Private Memory(mmap,共享存储器)分离的存储空间

如果在特定键上的 get是您执行的唯一操作,为什么不将所有键分别保存在缓存中?这样,所有条目将最终进入单独的文件,而Django将能够快速访问它们。

当然,更新会更加痛苦,但是您可以很好地抽象。我能想到的第一件事是一些缓存密钥前缀。

代码看起来像cache.get('{prefix}search_term')

编辑:

我们正在尝试在这里解决错误的问题。您不需要缓存。数据被更新,未倾倒(5分钟后)。

您需要创建一个带有所有条目的数据库表。

如果您无法从设置中访问任何数据库服务器,请尝试使用SQLite。它是基于文件的,应该很好地满足您的目的。

最新更新