我有一个字典对象,其中约有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。它是基于文件的,应该很好地满足您的目的。