如何销毁Python对象并释放内存
我试图迭代超过100,000个图像并捕获一些图像功能,并将所得的dataFrame作为pickle文件存储在磁盘上。
不幸的是,由于RAM的限制,我被迫将图像分成20,000个大块,并对它们执行操作,然后再将结果保存到磁盘上。
在开始循环以处理下一个20,000图像之前,下面编写的代码应该保存20,000图像的结果数据框。
但是-这似乎没有解决我的问题,因为在第一个for循环结束时内存没有从RAM中释放
因此,在处理第50,000条记录时,该程序由于内存不足错误而崩溃。
我尝试将对象保存到磁盘并调用垃圾收集器后删除这些对象,但是RAM的使用率似乎并未下降。
我想念什么?
#file_list_1 contains 100,000 imagesfile_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.
实际上,不能保证del
python中的显式s释放内存。
您应该 在 加入之后/之后使用:
with ThreadPool(..): ...
pool.join()
gc.collect()
您也可以尝试将其切成小块,例如10,000甚至更小!
锤子1
一件事,我会考虑在这里做,而不是使用pandas
DataFrames和大列表是使用SQL数据库,您可以使用sqlite3在本地进行此操作:
import sqlite3conn = 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