如何在 Python 中明确释放内存?
- 2024-11-26 08:37:00
- admin 原创
- 169
问题描述:
我编写了一个 Python 程序,它对大型输入文件进行操作,以创建几百万个表示三角形的对象。该算法如下:
读取输入文件
处理文件并创建一个三角形列表,以它们的顶点表示
以 OFF 格式输出顶点:顶点列表后跟三角形列表。三角形由顶点列表中的索引表示
OFF 要求我在打印三角形之前先打印出完整的顶点列表,这意味着我必须在将输出写入文件之前将三角形列表保存在内存中。与此同时,由于列表的大小,我遇到了内存错误。
告诉 Python 我不再需要某些数据并且可以释放它的最佳方法是什么?
解决方案 1:
根据Python 官方文档,你可以使用 明确调用垃圾收集器来释放未引用的内存gc.collect()
。例如:
import gc
gc.collect()
您应该在标记要丢弃的内容后执行此操作del
:
del my_array
del my_object
gc.collect()
解决方案 2:
不幸的是(取决于您的 Python 版本和发行版),某些类型的对象使用“空闲列表”,这是一种巧妙的局部优化,但可能会导致内存碎片,具体来说,通过使越来越多的内存“指定”用于仅特定类型的对象,从而无法用于“一般基金”。
确保大量但临时的内存使用在完成后确实将所有资源返回给系统的唯一真正可靠的方法是让该使用发生在子进程中,该子进程执行内存密集型工作然后终止。在这种情况下,操作系统将完成其工作,并乐意回收子进程可能已占用的所有资源。幸运的是,该multiprocessing
模块使这种操作(过去相当麻烦)在现代版本的 Python 中变得不那么糟糕。
在您的用例中,子流程积累一些结果并确保这些结果可供主流程使用的最佳方式似乎是使用半临时文件(半临时的意思是,不是关闭时自动消失的那种文件,只是在您完成所有操作后明确删除的普通文件)。
解决方案 3:
该del
语句可能有用,但 IIRC不能保证释放内存。文档在这里... 而为什么没有发布在这里。
我听说人们在 Linux 和 Unix 类型的系统上分叉一个 python 进程来做一些工作,获得结果然后杀死它。
这篇文章对 Python 垃圾收集器进行了说明,但我认为缺乏内存控制是托管内存的缺点
解决方案 4:
Python 具有垃圾收集功能,因此如果你减少列表的大小,它将回收内存。你也可以使用“del”语句完全删除变量:
biglist = [blah,blah,blah]
#...
del biglist
解决方案 5:
(del
可以成为你的朋友,因为当没有其他引用它们时,它会将对象标记为可删除。现在,CPython 解释器通常会保留这块内存以供以后使用,因此你的操作系统可能看不到“释放的”内存。)
也许您一开始就不会遇到任何内存问题,因为您使用的数据结构更紧凑。因此,数字列表的内存效率远低于标准array
模块或第三方numpy
模块使用的格式。您可以将顶点放在 NumPy 3xN 数组中,将三角形放在 N 元素数组中,这样可以节省内存。
解决方案 6:
您无法明确释放内存。您需要做的是确保不保留对对象的引用。然后它们将被垃圾收集,从而释放内存。
就你的情况而言,当你需要大型列表时,你通常需要重新组织代码,通常使用生成器/迭代器。这样,你根本不需要在内存中保存大型列表。
解决方案 7:
我在从文件中读取图形时遇到了类似的问题。处理包括计算 200 000x200 000 浮点矩阵(一次一行),该矩阵无法放入内存。尝试在计算之间释放内存,解决了与gc.collect()
内存相关的问题,但导致了性能问题:我不知道为什么,但即使使用的内存量保持不变,每次新的调用gc.collect()
都比前一次花费更多时间。因此,垃圾收集很快就占用了大部分计算时间。
为了解决内存和性能问题,我改用了曾经在某处读到过的一个多线程技巧(抱歉,我再也找不到相关的帖子了)。以前,我会在一个大for
循环中读取文件的每一行,然后处理它,并gc.collect()
每隔一段时间运行一次以释放内存空间。现在,我会在一个新线程中调用一个函数来读取和处理文件的一部分。一旦线程结束,内存就会自动释放,而不会出现奇怪的性能问题。
它的工作原理如下:
from dask import delayed # this module wraps the multithreading
def f(storage, index, chunk_size): # the processing function
# read the chunk of size chunk_size starting at index in the file
# process it using data in storage if needed
# append data needed for further computations to storage
return storage
partial_result = delayed([]) # put into the delayed() the constructor for your data structure
# I personally use "delayed(nx.Graph())" since I am creating a networkx Graph
chunk_size = 100 # ideally you want this as big as possible while still enabling the computations to fit in memory
for index in range(0, len(file), chunk_size):
# we indicates to dask that we will want to apply f to the parameters partial_result, index, chunk_size
partial_result = delayed(f)(partial_result, index, chunk_size)
# no computations are done yet !
# dask will spawn a thread to run f(partial_result, index, chunk_size) once we call partial_result.compute()
# passing the previous "partial_result" variable in the parameters assures a chunk will only be processed after the previous one is done
# it also allows you to use the results of the processing of the previous chunks in the file if needed
# this launches all the computations
result = partial_result.compute()
# one thread is spawned for each "delayed" one at a time to compute its result
# dask then closes the tread, which solves the memory freeing issue
# the strange performance issue with gc.collect() is also avoided
解决方案 8:
正如其他答案已经提到的,即使 Python 代码不再使用内存(因此gc.collect()
不会释放任何内容),Python 也可以阻止将内存释放给操作系统,尤其是在长时间运行的程序中。无论如何,如果您使用的是 Linux,您可以尝试通过直接调用 libc 函数malloc_trim
(手册页)来释放内存。类似:
import ctypes
libc = ctypes.CDLL("libc.so.6")
libc.malloc_trim(0)
解决方案 9:
其他人已经发布了一些方法,您可能能够“诱导”Python 解释器释放内存(或以其他方式避免出现内存问题)。您可能应该先尝试一下他们的想法。但是,我觉得直接回答您的问题很重要。
实际上没有任何方法可以直接告诉 Python 释放内存。事实上,如果您想要如此低级别的控制,您将不得不用 C 或 C++ 编写扩展。
话虽如此,还是有一些工具可以帮助解决这个问题:
赛通
痛饮
提升python
解决方案 10:
如果您不关心顶点重用,则可以有两个输出文件——一个用于顶点,一个用于三角形。完成后,将三角形文件附加到顶点文件。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)