手动释放Python内存:del与gc.collect()的实践解析

Felix
Felix
发布时间:2026-10-13| 1人浏览过
原创

本文通过实验揭示Python中del语句并不真正释放内存,而是归还给内存池。只有通过显式调用gc.collect()才能强制回收对象。文章对比了不同环境下的内存消耗峰值与实时状态,指出在多线程或特定场景下gc的触发时机可能受系统可用内存影响,建议结合del与gc.collect()以优化脚本内存表现。

在前一篇博客中,我们讨论了对某个脚本进行的多次优化。当时自认为优化已臻完善,然而在测试人员介入测试后,我才意识到自己掉进了Python的一个巨大陷阱。

此前的优化方案中,每处理500个用户便会执行计算并将结果写入磁盘文件。原本假设写入磁盘后,这些数据便不再占用内存;但Python的机制决定了它不会自动清理这部分内存。这一现象源于Python自身的实现原理,具体原因网上已有大量文章详述,此处不再赘述。

本篇博客将展示一个实验脚本,旨在证明Python确实存在不自动释放内存的现象,并提供一种解决方案:先使用del语句,再显式调用gc.collect()。脚本代码及具体效果如下所示。

实验环境一:Windows 7系统,Python 2.7版本。

from time import sleep, time 
import gc 
 
def mem(way=1): 
 print time() 
 for i in range(10000000): 
  if way == 1: 
   pass 
  else: # way 2, 3 
   del i 
    
 print time() 
 if way == 1 or way == 2: 
  pass 
 else: # way 3 
  gc.collect() 
 print time() 
   
if __name__ == "__main__": 
 print "Test way 1: just pass" 
 mem(way=1) 
 sleep(20) 
 print "Test way 2: just del" 
 mem(way=2) 
 sleep(20) 
 print "Test way 3: del, and then gc.collect()" 
 mem(way=3) 
 sleep(20) 
  

运行结果如下:

Test way 1: just pass 
1426688589.47 
1426688590.25 
1426688590.25 
Test way 2: just del 
1426688610.25 
1426688611.05 
1426688611.05 
Test way 3: del, and then gc.collect() 
1426688631.05 
1426688631.85 
1426688631.95 

对于Way 1和Way 2,结果完全一致。程序内存消耗峰值达到326772KB,在sleep 20秒时,实时内存消耗为244820KB。

对于Way 3,程序内存消耗峰值与前述相同,但在sleep期间,实时内存消耗降至仅6336KB。

实验环境二:Ubuntu 14.10系统,Python 2.7.3版本。

运行结果:

Test way 1: just pass 
1426689577.46 
1426689579.41 
1426689579.41 
Test way 2: just del 
1426689599.43 
1426689601.1 
1426689601.1 
Test way 3: del, and then gc.collect() 
1426689621.12 
1426689622.8 
1426689623.11 
ubuntu@my_machine:~$ ps -aux | grep test_mem 
Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html 
ubuntu 9122 10.0 6.0 270916 245564 pts/1 S+ 14:39 0:03 python test_mem.py 
ubuntu 9134 0.0 0.0 8104 924 pts/2 S+ 14:40 0:00 grep --color=auto test_mem 
ubuntu@my_machine:~$ ps -aux | grep test_mem 
Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html 
ubuntu 9122 10.0 6.0 270916 245564 pts/1 S+ 14:39 0:03 python test_mem.py 
ubuntu 9134 0.0 0.0 8104 924 pts/2 S+ 14:40 0:00 grep --color=auto test_mem 
ubuntu@my_machine:~$ ps -aux | grep test_mem 
Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html 
ubuntu 9122 11.6 0.1 30956 5608 pts/1 S+ 14:39 0:05 python test_mem.py 

结论:

以上实验表明,当调用del时,Python实际上并未真正释放内存,而是将其保留在内存池中;只有在显式调用gc.collect()时,才会真正执行内存释放操作。

进一步分析:

回顾上一篇博客中的脚本,我们引入gc.collect()并编写监控脚本来观察内存消耗情况:

while ((1)); do ps -aux | sort -n -k5,6 | grep my_script; free; sleep 5; done 

结果显示:内存并不会在每500个用户一组执行完毕后立即恢复,而是持续消耗,直到系统可用内存仅剩约70MB时,gc才似乎开始发挥作用。在本环境中,机器使用的是Cloud instance,总内存为2G,可用内存约为1G,该脚本的常规内存消耗在900M至1G之间。换言之,对于这个脚本而言,gc并未立即生效,而是在系统可用内存从1-1.2G下降至仅剩70M左右时,gc才开始起作用。这一点颇为奇怪,不确定是否与该脚本在Thread中使用gc.collect()有关,亦或是gc的作用机制本身不可控。笔者尚未对此进行相关实验,可能将在下篇博客中继续探讨。

但可以肯定的是,若不使用gc.collect(),原脚本将会耗尽系统内存并被系统杀死。这一点可以从syslog日志中明显看出。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。