python-3.x - Pandas DataFrame内存重新分配不会释放旧内存,很快就会导致OOM错误
问题描述
我的理解是float64
应该占用两倍的内存float32
。我使用的是 pandas DataFrame,当我向其中添加 float32 列时,内存消耗非常低。但是,当我向其中添加float64
列时,内存消耗的行为方式使我无法绕开我的脑袋
我正在使用以下代码来研究这两种行为:
为了float32
import numpy as np
import pandas as pd
narr = np.random.rand(500,1000000)
df = pd.DataFrame(narr)
for c, i in enumerate(df.columns):
print(c,end='\r')
df[str(i)+'dummy'] = (df[i].values/df[0].values).astype(np.float32)
以下是我每 100 次迭代记录的内存消耗(以 GB 为单位):
- 0 - 4.29
- 100 - 4.43
- 200 - 4.43
- 300 - 4.43
- 400 - 4.44
- 500 - 4.44
现在,对于 float64
代码:
import numpy as np
import pandas as pd
narr = np.random.rand(500,1000000)
df = pd.DataFrame(narr)
for c, i in enumerate(df.columns):
print(c,end='\r')
df[str(i)+'dummy'] = (df[i].values/df[0].values).astype(np.float64)
这里的行为很奇怪。每 100 次迭代:
- 迭代暂停了一段时间
- 内存消耗大约增加 5GB
- 内存消耗下降 1-4 GB
- 迭代继续,并且内存消耗在接下来的 100 次迭代中保持不变(稳定)
- 该过程从步骤 1 开始重复
- itr - 稳定,最大
- 0 - 4.29, 4.29
- 100 - 8.17, 10.5
- 200 - 11.9, 15.2
- 300 - 15.7, 16.4
- 400 - 19.4, 21.5
- 500 - 23.1, 26.7
请帮助我理解:
- 为什么内存消耗不是简单的
float64
=float32
*2 关系? - 为什么奇怪的内存增量模式
float64
?它似乎每 100 次迭代就会增加一次,它也首先显着上升,然后略微下降,并在接下来的 100 次迭代中保持在那里
编辑:我按照@hpaulj 的评论中的建议使用了 df._mgr。它揭示了:
- pandas 将所有相似的 dtyped 列组合在一个内存块中
- 添加到 DataFrame 的每个新列都作为单独的内存块添加
- pandas 可以拥有的最大内存块数是 100
- 因此,每 100 次迭代 pandas 会打乱数据集并重新分配内存,并在此过程中将相似 dtyped 块的内存块合并在一起
- 所以,问题实际上是,如果创建的初始数据集是dtype 的,
floatx
那么添加floatx
dtyped 的新列将导致内存消耗爆炸。之所以会发生这种情况,是因为 pandas 会将整个 old_columns+new_columns 重新分配一个新的连续内存块并腾出较早的综片内存位置
我无法理解为什么会这样。有人会认为,一旦整个 DataFrame 被重新分配,那么 DataFrame 占用的旧内存位置就会被释放,但显然情况并非如此。
这是典型的内存泄漏案例吗?如果 Pandas 不负责释放旧内存,那就太奇怪了。
另外,我仍然不明白为什么在每 100 次迭代重新分配时,内存消耗会比它最终稳定下来的还要多。似乎熊猫确实释放了一些内存,但不是全部?
欢迎所有见解。
解决方案
推荐阅读
- spring - Spring:SecurityContextHolder.getContext().getAuthentication() 在 iFrame 中返回 Anonymousauthenticationtoken
- numpy - 重塑变量 numpy 数组
- python - 无法启动 docker VM:ImportError: cannot import name 'format_lazy' from 'django.utils.text'(Python 错误)
- ios - 我收到“ WARN | url: (homepage) URL is not reachable。” 在 iOS pod lib lint 命令上?
- php - 为什么 phpinfo() 显示的版本与 php -v 不同?
- php - 如何在 php mysql 中汇总递归循环的奖金?
- jquery - 更改通过 jquery 中的 .after 方法加载的 div 的值/内容
- ios - IOS swift tableview get headerview for a section
- node.js - NodeJS/Express 使用多个 req.query.params 构建 URL
- php - 无法在 PDO 中使用 AJAX 进行产品过滤的 $_GET 数据