我有一个字典对象,有大约60,000个密钥,我在Django视图中缓存和访问。该视图提供了基本的搜索功能,我在字典中查找搜索词,如下所示:
projects_map = cache.get('projects_map')
projects_map.get('search term')
然而,只是抓住缓存的对象(在第1行)会导致服务器上的内存使用量大幅增加 - 有时超过100MB - 即使在返回值并呈现模板后内存也不会释放。 / p>
如何保持内存不会像这样抬起?此外,我尝试在获取值后显式删除对象,但即使这样也不会释放内存峰值。
非常感谢任何帮助。
我决定实现自己的索引表,在其中存储密钥及其pickle值。现在,我使用:
而不是在字典上使用get()
ProjectsIndex.objects.get(index_key=<search term>)
并取消该值。这似乎解决了内存问题,因为我不再将巨型对象加载到内存中。它为页面添加了另一个小查询,但这就是它。现在似乎是一个完美的解决方案。
答案 0 :(得分:4)
..如何使用一些适当的缓存服务,如redis或memcached而不是在内存python端加载巨大的对象?这样,如果字典增长更多,你甚至可以扩展额外的机器。
无论如何,100MB内存包含所有数据+哈希索引+ misc。高架;前几天我注意到很多次内存都没有被释放,直到你退出Python进程(我从Python解释器填充了几个内存,加载了一个巨大的json对象.. :));如果任何人都有解决方案,这将是有趣的..
只有512MB RAM的选项是:
并且,在后两种情况下,尝试拆分对象,这样就不会一次从缓存中检索数兆字节的对象。
你可以用这样的东西替换你的缓存字典;这样,您可以像使用普通字典一样继续处理它,但只有在您真正需要时才会从缓存加载数据。
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')
使用:
projects_map = LazyCachedDict('projects_map')
projects_map.get('search term')
答案 1 :(得分:0)
我不知道Windows是如何工作的,但在Linux中,一个进程实际上无法将内存返回给系统。这是因为进程地址空间是连续的,并且唯一可用的增加内存的系统调用是brk()
,它只会增加一个指针,该指针标记进程可用的最后一个地址。
应用程序使用(malloc
等)的所有分配器都在用户空间中定义为库。它们在字节块级别上运行,并使用brk()
仅增加内部内存池。在正在运行的应用程序中,此内存池与请求的块混杂在一起。将内存返回给系统的唯一可能性是当池的最后一部分没有使用块时(这不太可能,因为即使是简单的应用程序也会分配和释放数千个对象)。
因此记忆飙升引起的膨胀将一直持续到最后。解决方案:
gdbm
)或与进程'私有内存(mmap
,共享内存)分离的其他存储答案 2 :(得分:0)
如果特定键上的get
是您执行的唯一操作,为什么不将所有键分别保存在缓存中?这样,所有条目都将以单独的文件结束,django将能够访问它们quickly。
当然,更新会更加痛苦,但你可以很好地抽象它。我能想到的第一件事就是一些缓存键前缀。
代码看起来像cache.get('{prefix}search_term')
。
修改强>
我们在这里试图解决错误的问题。您不需要缓存。数据得到更新,而不是转储(5分钟左右)。
您需要创建一个包含所有条目的数据库表。
如果您无法从您的设置访问任何数据库服务器,请尝试使用sqlite。它是基于文件的,应该很好地满足您的目的。