在python中,函数调用后不会释放内存

在python中,函数调用后不会释放内存,python,pandas,memory,garbage-collection,Python,Pandas,Memory,Garbage Collection,我已经玩了一段时间memory\u profiler,从下面的小程序中得到了这个有趣但令人困惑的结果: 将熊猫作为pd导入 将numpy作为np导入 @侧面图 def f(p): tmp=[] 对于u,p.iteritems()中的框架: tmp.append([list(record)for frame.to_records(index=False)]) #初始化面板列表 lp=[] 对于X范围内的j(50): d={} 对于X范围内的i(50): df=pd.DataFrame(np.ran

我已经玩了一段时间
memory\u profiler
,从下面的小程序中得到了这个有趣但令人困惑的结果:

将熊猫作为pd导入
将numpy作为np导入
@侧面图
def f(p):
tmp=[]
对于u,p.iteritems()中的框架:
tmp.append([list(record)for frame.to_records(index=False)])
#初始化面板列表
lp=[]
对于X范围内的j(50):
d={}
对于X范围内的i(50):
df=pd.DataFrame(np.random.randn(200,50))
d[i]=df
lp.追加(pd.面板(d))
#执行(迭代)
对于lp中的面板:
f(小组)
然后,如果我使用memory_profiler的mprof来分析运行时的内存使用情况,
mprof run test.py
而不使用任何其他参数,我会得到以下结果: .

在每次函数调用f()之后,似乎都有未释放的内存

tmp
只是一个本地列表,应该在每次调用f()时重新分配和重新分配内存。很明显,所附图表中存在一些差异。我知道python有自己的内存管理块,也有int和其他类型的空闲列表,
gc.collect()
。结果是显式的
gc.collect()
不起作用。(可能是因为我们正在处理熊猫对象、面板和框架?我不知道。)

最令人困惑的是,我没有更改或修改
f()
中的任何变量。它所做的只是将一些列表表示副本放在本地列表中。因此,python不需要复制任何内容。那么为什么会这样,又是如何发生的呢

=================

其他一些意见:

1) 如果使用
f(panel.copy())
(代码的最后一行)调用
f()
,并传递副本而不是原始对象引用,则会得到完全不同的内存使用结果:。python是否明智地判断传递的这个值是一个副本,以便它可以在每次函数调用后执行一些内部技巧来释放内存

2) 我想这可能是因为df.to_records()。如果我把它改为
frame.values
,我会得到类似的平坦内存曲线,就像上面显示的
memory\u profiling\u results\u 2.png
一样,在迭代过程中(尽管我确实需要
来记录()
,因为它维护列数据类型,而
values
会弄乱数据类型)。但是我研究了frame.py在
to_records()
上的实现。我不明白为什么它会保留内存,而
.values
会正常工作


我正在Windows上运行该程序,使用python 2.7.8、memory_profiler 0.43和psutil 5.0.1。这不是内存泄漏。您看到的是
pandas.core.NDFrame
缓存某些结果的副作用。这允许它在您第二次请求时返回相同的信息,而无需再次运行计算。将示例代码的结尾更改为与以下代码类似,然后运行它。您应该发现,第二次内存增加不会发生,执行时间也会减少

import time

# execution (iteration)
start_time = time.time()
for panel in lp:
    f(panel)
print(time.time() - start_time)

print('-------------------------------------')
start_time = time.time()
for panel in lp:
    f(panel)
print(time.time() - start_time)

首先谢谢你的回答!是的,我也试过了,并且意识到这不是一个漏洞!您说过这是缓存的副作用。你知道缓存发生在哪里吗?或者如何?因为我做了一些类似的实验,结果证明缓存并不是每次都发生。例如,如果我在这里使用
.values
而不是
来记录()
我不会看到内存增加。你能告诉我pandas核心在哪里实现缓存吗?或者简单地向我解释缓存何时会进入我们的方式?有办法解决吗?使用
.copy()
?我需要“修复”这个问题的原因是,如果我有一个较长的列表,并且
lp
现在由500个对象组成,内存将增加得太多。使用调试器(我使用
pycharm
),你可以进入
pandas
代码,看看它是如何工作的。感谢@stephenauch指出这一点。这方面的更新:这是由于数据帧的熊猫缓存。当调用
\u getitem\u()
以访问数据帧的列时,每列都将存储到
\u item\u缓存中。在这种情况下,这是因为
pd.to_records()
有一个列表理解,其中包括
self[c]for…
。事实上,所有的数据帧都在调用后被缓存。有没有办法避免缓存或解决这个问题?