Python在numpy数组列表上循环时占用内存

2024-09-29 01:22:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用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和{}是几千个浮点数的numy数组,self.shuttertimes是一个有三个浮点数的numy数组。在

在这个循环的处理过程中(需要几分钟时间),我可以观察到Python的内存使用量逐渐增加,直到循环结束时比启动时多出6GB的内存。在

我使用memory_profiler和{}来分析内存使用情况,但没有成功。我知道在循环前后,self.dataself.TOFself.N_TRIGS,和{}保持相同的大小,并且拥有相同数量和相同类型的元素。如果我正确地理解了这一点,那么occupied _prob这样的局部变量在for循环的每次迭代之后都应该超出作用域,否则,在函数返回主循环之后,所有冗余内存都应该被垃圾回收。这不会发生,并且6GB将保持锁定状态,直到脚本终止。我还尝试使用gc.collect()运行手动垃圾回收,但没有任何结果。在

如果有帮助的话,这个函数存在于线程中,并且是更大的数据分析过程的一部分。没有其他线程尝试并发访问数据,并且在线程退出后,self.data被复制到另一个类中。然后线程的实例会因超出范围而被销毁。我还试图使用del thread_instancethread_instance = None手动销毁线程,但6GB仍然被锁定。这在开发机器上不是一个大问题,但是代码将是一个更大的包的一部分,这个包可能在RAM有限的机器上运行。在


Tags: 内存selfnumpy列表dataindexnp数组
1条回答
网友
1楼 · 发布于 2024-09-29 01:22:26

我设法找到了解决这个问题的办法。TL;DR:在函数执行期间,self.datadtype没有被强制执行。在

第一个让我无法意识到这一点的问题是,通过使用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

self.data = np.asarray(self.data, dtype='uint16')

相关问题 更多 >