根据其他帖子,我了解Django没有内存泄漏问题,但我有一个web应用程序,当我特定的例程被调用时,很多内存被使用,但不是所有的内存都被释放了。我不知道这是否是正确的术语,但如果我在AWS上跟踪mem_used_perc,而只在网页上调用这个例程,我看到内存使用增加,而不是返回到以前的水平。
这是一个递归例程,我调用它可以迭代多达7次。这是代码:
def autosearch(self, phase=1, report="", num = 10):
"""
This is an ES search following specific rules to identify and populate
the lead notifications
"""
if phase == 1:
self.referred_to.clear()
if self.no_of_providers:
num = self.no_of_providers
else:
num = 10
sqs = OrganisationDocument.search()
service_type = None
# filter by care type
if self.type_of_care_care_home:
service_type = "service_care_home"
elif self.type_of_care_home_care:
service_type = "service_home_care"
elif self.type_of_care_live_in_care:
service_type = "service_live_in_care"
elif self.type_of_care_retirement_village:
service_type = "service_retirement_village"
if service_type == "service_retirement_village":
sqs = sqs.query(Q("multi_match", query=True, fields=service_type))
elif service_type:
sqs = sqs.query(
Q("multi_match", query=True, fields=service_type)
& Q("match", care_over_65=True)
)
else:
sqs = sqs.query(Q("match", care_over_65=True))
if self.budget_type:
ranges = self.filter_by_budget_range(phase)
sqs = sqs.query(Q("bool", should=list(ranges)))
# filter on location and distance
if self.radius:
radius = self.radius
else:
radius = 5
"""Increase radius by 2 or 10% for phase 2, 5, and 6"""
if phase in [2, 6]:
if radius < 20:
radius += 2
else:
radius *= 1.1
sqs = sqs.query(
"geo_distance",
distance=f"{radius}mi",
location={
"lat": self.searcharea_set.all()[0].lat,
"lon": self.searcharea_set.all()[0].lng,
},
)
# Filter by care_category_type
categories = []
if self.care_need_category_residential:
categories.append("care_residential")
if self.care_need_category_nursing:
categories.append("care_nursing")
if self.care_need_category_dementia:
categories.append("care_dementia")
if self.care_need_category_nursing_dementia:
pass
if self.care_need_category_personal_care:
categories.append("care_residential")
if self.care_need_category_respite_care:
categories.append("care_respite")
if self.care_need_palliative:
pass
if self.care_need_end_of_life:
pass
if self.care_need_retirement_housing:
categories.append("retirement_living_housing")
if self.care_need_retirement_village:
categories.append("retirement_living_village")
if self.care_need_retirement_community:
categories.append("retirement_living_community")
if self.care_need_retirement_full_time:
pass
query = []
for category in categories:
if self.type_of_care_live_in_care or self.type_of_care_home_care:
if category == "care_residential":
category = "regulated_personal_care"
if category == "care_nursing":
query.append(
Q(
Q("match", regulated_nursing_care=True)
| Q("match", care_nursing=True)
)
)
else:
query.append(Q("match", **{f"{category}": True}))
if self.type_of_care_retirement_village:
sqs = sqs.query("bool", should=list(query))
else:
sqs = sqs.filter(Q("bool", must=query))
# CQC Regulator filter
sqs = sqs.query(
Q(
Q("match", cqc_rating_overall=1)
| Q("match", cqc_rating_overall=2)
| Q("match", cqc_rating_overall=3)
| Q("match", cqc_rating_overall=99)
)
)
# filter on profile
if phase >= 4:
sqs = sqs.query(Q("match", has_thumbnail_image=1))
# Exclude Standard profiles in Brand with Premium Profile
prems = [x.id for x in self.referred_to.all() if x.is_premium]
sqs = sqs.query(~Q('bool', brand_link=list(prems)))
else:
sqs = sqs.query(Q("match", is_premium=1))
# filter on budget
if self.budget_type:
ranges = self.filter_by_budget_range(phase)
sqs = sqs.query(Q("bool", should=list(ranges)))
# funding method
if self.funding_method == choices.LOCAL_AUTHORITY:
sqs = sqs.query(~Q("match", fees_local_authority_funded=False))
# sqs = sqs.query('match', **{'fees_local_authority_funded': True})
elif self.funding_method == choices.SELF_FUNDING:
sqs = sqs.query("match", self_funding_clients=True)
elif self.funding_method == choices.CONTINUING_HEALTHCARE:
sqs = sqs.query(Q("match", fees_continuous_health_top_up=True))
elif self.funding_method == choices.TOP_UP:
sqs = sqs.query(~Q("match", fees_family_top_up=False))
# Red crossed
sqs = sqs.query(~Q("match", autumna_flag=2))
# amber flagged
if phase < 7:
sqs = sqs.query(~Q("match", autumna_flag=1))
# email only
if not self.may_contact_provider:
sqs = sqs.query(~Q("match", leads_accepted=1))
sqs = sqs.query(~Q("match", leads_accepted=2))
# no permission
if not self.may_contact_phone:
sqs = sqs.query(~Q("match", leads_accepted=1))
# timescales
if self.timescales in ["ASAP", "2-4 weeks"]:
sqs = sqs.query(
Q(
Q("match", availability_overall=1)
| Q("match", availability_overall=2)
)
)
sqs.sort("-is_premium", "-has_thumbnail_image", "-is_claimed", self.sort_geo_location_dict())
sqs = sqs[:num]
report += f"<p>Phase {phase}:"
added_count = 0
for organisation in sqs.to_queryset():
if not organisation in self.referred_to.all():
added_count += 1
self.referred_to.add(organisation)
report += f"{organisation}, "
report += "</p>"
if added_count >= num or phase >= 7:
self.autosearch_interim_report = report
self.save()
else:
phase += 1
num -= added_count
return self.autosearch(phase, report, num)
return True
是否有任何原因会导致我所看到的症状?我该如何解决?
编辑
从admin调用该函数,命令如下:
def autosearch(self, request, pk):
"""
Populates the lead notifications
"""
lead = get_object_or_404(models.Lead, pk=pk)
# first, add organisations to favourites
result = lead.autosearch()
logger.debug(f'Auto search result: {result}')
return redirect(reverse("admin:lead_management_lead_change", args=(pk,)))
编辑
我正在使用Memcache,定义如下:
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
"LOCATION": os.environ.get("CACHE_LOCATION", "127.0.0.1:11211"),
}
}
本地我在机器上运行但在生产中,我使用Elastic Beanstalk中的环境变量来定义CACHE_LOCATION
这是一个字符串my-site-name-prod.abcdef.cfg.euw2.cache.amazonaws.com:11211
编辑
def filter_by_budget_range(self, phase):
"""
How the function works:
- case 1: When a given value of min and max budget
- It simply filter organisations between this range.
- case 2: When a given value is only max budget
- From given max budget we derived the min budget
- min_budget = max_budget - max_budget * 0.2
- e.g max_budget = 100, then the min_budget = 100 - 100 * 0.2 => 80
- case 3: When a given value is only min budget
- From given min budget we derived the max budget
- max_budget = min_budget + min_budget * 0.2
- e.g min_budget = 100, then the max_budget = 100 + 100 * 0.2 => 120
"""
_budget_min, _budget_max = self.min_max_handler(phase)
if _budget_max is not None:
if self.type_of_care_live_in_care or self.type_of_care_care_home:
yield {
"range": {
"fees_weekly_residential_costs_from": {
"gte": _budget_min * 100,
"lte": _budget_max * 100,
}
}
}
else:
yield {
"range": {
"fees_hourly_start_from": {
"gte": _budget_min * 100,
"lte": _budget_max * 100,
}
}
}
所提供的代码中没有任何可以解释内存泄漏的内容。
问题一定来自其他地方(可能是self.filter_by_budget_range(phase)
)。
通常情况下,Django中的内存泄漏来自于使用在服务器启动时创建的对象时的副作用,并且您甚至没有意识到不断输入新数据,或者没有意识到该对象绑定到服务器而不是单个请求。
例如,如果你有这样的东西:
class Foobar(models.Model):
...
baz = ""
...
def barfoo(self, baz):
...
self.baz += baz
...
对于每个调用obj.barfoo(some_string)
的请求,Foobar.baz
将继续增长,直到服务器重新启动。
类似地,在下面的例子中:
def foobar(baz=[]):
...
baz.append(something)
...
在服务器启动时创建函数foobar
。每次使用默认参数调用foobar()
时,baz
都会一直增长,直到服务器重新启动。
这两个例子当然是愚蠢的,它只是展示了影响内存的副作用的简单案例。
另一个可能的问题是,如果你缓存一些东西使用基于内存的后端,如Memcached。
如果您不知道它可能是什么,您最好的选择可能是尝试在开发中重现问题并使用pdb
(甚至django-pdb
)来检查内存,无论是在运行开发服务器时还是直接在shell中(如果您可以在shell中重现,这可能更方便)。
手动运行gc是否有帮助?在代码中收集?
https://docs.python.org/3/library/gc.html
collect(): This method free the non referenced object in the list that is maintained by the Collector. Some non-referenced objects are not immediately free automatically due to their implementation.
==============================================
你确定你的问题是内存没有被释放吗?你的记忆力有问题吗?
在linux中,即使在程序再次释放内存之后,内存仍然被使用是典型的,因为,如果您一直保持内存为空,那对您的RAM有什么好处呢?即使你的应用程序现在不需要,操作系统也会把东西缓存在RAM中,因为当应用程序以后再次需要这些数据时,它可能会从性能的提高中受益,而这些数据仍然在你的RAM中。
这叫做:caching
我试着查找mem_used[_percent]调用的文档,我不太清楚这是指使用内存(应用程序+缓存)还是应用程序使用的内存https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/metrics-collected-by-CloudWatch-agent.html
您的空闲内存有问题吗?您的服务器内存不足吗?
。调用完成后,mem_available和mem_free是否会恢复?
您通常可以看到的是内存被应用程序使用,然后被释放,但由操作系统兑现。
所以mem_free会上升,但是它是在内存中被兑现的,所以mem_cached会上升,而mem_used保持不变。
这可以解释您在没有内存泄漏的情况下看到的内容。
。在我当前的系统上,当我执行cat /proc/meminfo
时,我看到几乎没有空闲的内存,但大部分(68%)被缓存占用,一旦应用程序需要内存,这些缓存就会被清除。
1 │ MemTotal: 16068712 kB
2 │ MemFree: 178332 kB
3 │ MemAvailable: 10290764 kB
4 │ Buffers: 812504 kB
5 │ Cached: 10203120 kB
6 │ SwapCached: 1596 kB
7 │ Active: 4852664 kB
8 │ Inactive: 10034536 kB