我正在使用python3和Numpy进行一些科学数据分析,我面临一个与内存相关的问题。当循环查看numpy数组列表(其中几千个)并进行一些中间计算时,我注意到python占用的内存比我预期的要多6GB。我已经将问题隔离到一个功能,如下所示:
def overlap_correct(self):
running_total = np.zeros((512, 512))
shutter = 0
for data_index in range(len(self.data)):
if self.TOF[data_index] < self.shutter_times[shutter]:
occupied_prob = running_total/self.N_TRIGS[data_index]
running_total += self.data[data_index]
self.data[data_index] = np.round(np.divide(self.data[data_index], (1 - occupied_prob)))
else:
running_total = np.zeros((512, 512))
shutter += 1
这里的相关数据结构是self.data
,它是一个具有一千个512x512 numpy数组的列表,self.TOF
和{self.shutter
times是一个有三个浮点数的numy数组。在
在这个循环的处理过程中(需要几分钟时间),我可以观察到Python的内存使用量逐渐增加,直到循环结束时比启动时多出6GB的内存。在
我使用memory_profiler
和{self.data
,self.TOF
,self.N_TRIGS
,和{occupied _prob
这样的局部变量在for
循环的每次迭代之后都应该超出作用域,否则,在函数返回主循环之后,所有冗余内存都应该被垃圾回收。这不会发生,并且6GB将保持锁定状态,直到脚本终止。我还尝试使用gc.collect()
运行手动垃圾回收,但没有任何结果。在
如果有帮助的话,这个函数存在于线程中,并且是更大的数据分析过程的一部分。没有其他线程尝试并发访问数据,并且在线程退出后,self.data
被复制到另一个类中。然后线程的实例会因超出范围而被销毁。我还试图使用del thread_instance
和thread_instance = None
手动销毁线程,但6GB仍然被锁定。这在开发机器上不是一个大问题,但是代码将是一个更大的包的一部分,这个包可能在RAM有限的机器上运行。在
我设法找到了解决这个问题的办法。TL;DR:在函数执行期间,
self.data
的dtype
没有被强制执行。在第一个让我无法意识到这一点的问题是,通过使用
sys.getsizeof()
来查看self.data
在内存中占用了多少空间,我得到了指向numpy.ndarray
对象的指针列表的大小,这与数组的数量没有变化一样。在其次,当我检查
self.data[0]
的dtype
,这是唯一不变的数据“幻灯片”,我错误地认为整个数组列表也有相同的dtype
。在我怀疑某些数组的
dtype
被更改的原因是np.round()
返回一个取整的float
。在通过将
self.data
的结构从几千个256x256数组的列表更改为[a few thousand]x[256]x[256]
的三维数组,函数不再猜测数据的dtype
,而是静默地将np.round
返回的float64
强制转换为uint16
:相关问题 更多 >
编程相关推荐