【发布时间】:2020-08-07 08:21:31
【问题描述】:
我有一个使用 Google 数据存储的网络应用程序,但在请求足够多后内存不足。
我已将其范围缩小到数据存储区查询。下面提供了最低 PoC,包含内存测量的 slightly longer version 在 Github 上。
from google.cloud import datastore
from google.oauth2 import service_account
def test_datastore(entity_type: str) -> list:
creds = service_account.Credentials.from_service_account_file("/path/to/creds")
client = datastore.Client(credentials=creds, project="my-project")
query = client.query(kind=entity_type, namespace="my-namespace")
query.keys_only()
for result in query.fetch(1):
print(f"[+] Got a result: {result}")
for n in range(0,100):
test_datastore("my-entity-type")
分析过程 RSS 显示每次迭代大约 1 MiB 增长。即使没有返回结果,也会发生这种情况。以下是我的 Github gist 的输出:
[+] Iteration 0, memory usage 38.9 MiB bytes
[+] Iteration 1, memory usage 45.9 MiB bytes
[+] Iteration 2, memory usage 46.8 MiB bytes
[+] Iteration 3, memory usage 47.6 MiB bytes
..
[+] Iteration 98, memory usage 136.3 MiB bytes
[+] Iteration 99, memory usage 137.1 MiB bytes
但同时,Python 的mprof 显示了一个平面图(像mprof run python datastore_test.py 一样运行):
问题
我调用 Datastore 的方式是否有问题,或者这可能是库的潜在问题?
环境是 Windows 10 上的 Python 3.7.4(也在 Docker 中的 Debian 3.8 上进行了测试),google-cloud-datastore==1.11.0 和 grpcio==1.28.1。
编辑 1
澄清这不是典型的 Python 分配器行为,它从操作系统请求内存,但不会立即从内部竞技场/池中释放它。下面是来自 Kubernetes 的图表,我的受影响的应用程序在其中运行:
这表明:
- 内存线性增长,直到大约 2GiB,应用程序实际上崩溃了,因为它内存不足(从技术上讲,Kubernetes 驱逐了 pod,但这与这里无关)。
- 运行相同的 Web 应用程序,但没有与 GCP 存储或数据存储区交互。
- 仅添加了与 GCP 存储的交互(随着时间的推移非常轻微的增长,可能是正常的)。
- 仅添加了与 GCP 数据存储的交互(更大的内存增长,一小时内大约 512MiB)。 Datastore 查询与本文中的 PoC 代码完全相同。
编辑 2
为了绝对确定 Python 的内存使用情况,我使用 gc 检查了垃圾收集器的状态。退出前,程序报告:
gc: done, 15966 unreachable, 0 uncollectable, 0.0156s elapsed
我还在循环的每次迭代期间使用gc.collect() 手动强制垃圾收集,这没有任何区别。
由于没有不可回收的对象,内存泄漏似乎不太可能来自使用 Python 的内部内存管理分配的对象。因此,外部 C 库更有可能发生内存泄漏。
可能相关
有一个open grpc issue 我不能确定是否相关,但与我的问题有许多相似之处。
【问题讨论】:
标签: python memory-leaks google-cloud-datastore