如何销毁Python对象并释放内存

我试图迭代超过100,000个图像并捕获一些图像功能,并将所得的dataFrame作为pickle文件存储在磁盘上。

不幸的是,由于RAM的限制,我被迫将图像分成20,000个大块,并对它们执行操作,然后再将结果保存到磁盘上。

在开始循环以处理下一个20,000图像之前,下面编写的代码应该保存20,000图像的结果数据框。

但是-这似乎没有解决我的问题,因为在第一个for循环结束时内存没有从RAM中释放

因此,在处理第50,000条记录时,该程序由于内存不足错误而崩溃。

我尝试将对象保存到磁盘并调用垃圾收集器后删除这些对象,但是RAM的使用率似乎并未下降。

我想念什么?

#file_list_1 contains 100,000 images

file_list_chunks = list(divide_chunks(file_list_1,20000))

for count,f in enumerate(file_list_chunks):

# make the Pool of workers

pool = ThreadPool(64)

results = pool.map(get_image_features,f)

# close the pool and wait for the work to finish

list_a, list_b = zip(*results)

df = pd.DataFrame({'filename':list_a,'image_features':list_b})

df.to_pickle("PATH_TO_FILE"+str(count)+".pickle")

del list_a

del list_b

del df

gc.collect()

pool.close()

pool.join()

print("pool closed")

回答:

现在,可能是第50,000位的数据非常大,这导致了OOM,因此要对此进行测试,我将首先尝试:

file_list_chunks = list(divide_chunks(file_list_1,20000))[30000:]

如果它在10,000处失败,这将确认20k的块大小是否太大,或者如果再次在50,000处失败,则代码存在问题…


好的,进入代码…

首先,您不需要显式list构造函数,在python中进行迭代比将整个列表生成到内存中要好得多。

file_list_chunks = list(divide_chunks(file_list_1,20000))

# becomes

file_list_chunks = divide_chunks(file_list_1,20000)

我认为您可能在这里滥用ThreadPool:

阻止将更多任务提交给池。所有任务完成后,工作进程将退出。

这听起来像close有些想法仍在运行,尽管我认为这是安全的,但感觉有点不符合Python风格,最好将上下文管理器用于ThreadPool:

with ThreadPool(64) as pool: 

results = pool.map(get_image_features,f)

# etc.

实际上,不能保证delpython中的显式s释放内存。

您应该 加入之后/之后使用:

with ThreadPool(..):

...

pool.join()

gc.collect()

您也可以尝试将其切成小块,例如10,000甚至更小!


锤子1

一件事,我会考虑在这里做,而不是使用pandas

DataFrames和大列表是使用SQL数据库,您可以使用sqlite3在本地进行此操作:

import sqlite3

conn = sqlite3.connect(':memory:', check_same_thread=False) # or, use a file e.g. 'image-features.db'

并使用上下文管理器:

with conn:

conn.execute('''CREATE TABLE images

(filename text, features text)''')

with conn:

# Insert a row of data

conn.execute("INSERT INTO images VALUES ('my-image.png','feature1,feature2')")

这样,我们就不必处​​理大型列表对象或DataFrame。

您可以将连接传递给每个线程…您可能需要做些奇怪的事情:

results = pool.map(get_image_features, zip(itertools.repeat(conn), f))

然后,计算完成后,您可以从数据库中选择所有格式,并选择所需的格式。例如,使用read_sql。


锤子2

在这里使用一个子进程,而不是在python的“ shell out”的另一个实例中运行该子进程。

由于您可以将sys.args作为起点和终点传递给python,因此可以对它们进行切片:

# main.py

# a for loop to iterate over this

subprocess.check_call(["python", "chunk.py", "0", "20000"])

# chunk.py a b

for count,f in enumerate(file_list_chunks):

if count < int(sys.argv[1]) or count > int(sys.argv[2]):

pass

# do stuff

这样,子进程将正确清理python(由于进程将终止,因此不会有内存泄漏)。


我敢打赌,Hammer

1是必经之路,感觉就像您要粘贴大量数据,并不必要地将其读取到python列表中,而使用sqlite3(或其他一些数据库)完全可以避免这种情况。

以上是 如何销毁Python对象并释放内存 的全部内容, 来源链接: utcz.com/qa/413898.html

回到顶部