You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python脚本疑似内存泄漏求助:处理FITS文件时循环崩溃

Python脚本内存泄漏引发OOM崩溃问题排查与解决

问题背景

运行Python脚本循环处理.fits文件:绘图并手动选点,将结果保存到.dat文件。该脚本在其他设备运行正常,但在新笔记本上仅完成3-4次外层循环后就崩溃,终端被直接终止或自行关闭。通过内存监控和系统日志确认,是内存耗尽被OOM Killer杀死。

脚本代码

import numpy as np
from matplotlib import pyplot as plt
from astropy.io import fits,ascii
from glob import glob
import gc

list_files=np.sort(glob('*.fits')) ### around 90 objects 
list_ranges=ascii.read('ranges.dat')#### aroung 1000 objects
for i in range(len(list_files)):
    output = open(list_files[i]+'.dat','w')
    with fits.open(list_files[i]) as single_file:
        x=single_file[0].data[0]
        y=single_file[0].data[1]
    for j in range(len(list_ranges)):
        x_single=x[((x<list_ranges[j]+3) & (x>list_ranges[j]-3))]
        y_single=y[((x<list_ranges[j]+3) & (x>list_ranges[j]-3))]
        fig, ax = plt.subplots(figsize=(18,8))
        ax.plot(x,y)
        pts = np.asarray(plt.ginput(2, timeout=-1))
        output.write('%.2f %.2f\n'%(pts[0,0],pts[1,0]))
        plt.close()
        del x_single,y_single,pts
        gc.collect()
    output.close()
    del single_file,x,y
    gc.collect()

内存监控信息

  • 初始内存状态:
total        used        free      shared  buff/cache   available
Mem:            15Gi       2.6Gi       8.5Gi       754Mi       4.2Gi        11Gi
Swap:          2.0Gi          0B       2.0Gi
  • 处理第三个文件后的内存状态:
total        used        free      shared  buff/cache   available
Mem:            15Gi       5.5Gi       175Mi       7.8Gi       9.7Gi       1.7Gi
Swap:          2.0Gi       3.0Mi       2.0Gi

OOM Killer日志(dmesg输出)

[ 5783.416916] oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/user.slice/user-1000.slice/user@1000.service/app.slice/app-org.gnome.Terminal.slice/vte-spawn-94017a15-e67f-4443-87c5-a39220aa3d9c.scope,task=python3,pid=9500,uid=1000
[ 5783.416977] Out of memory: Killed process 9500 (python3) total-vm:9479428kB, anon-rss:4419828kB, file-rss:0kB, shmem-rss:2580kB, UID:1000 pgtables:14068kB oom_score_adj:0

解决方案

  • 修复Matplotlib绘图资源泄漏:将plt.close()改为plt.close(fig),明确关闭每个创建的Figure对象,避免未释放的绘图资源累积。每次绘图后可先清除Axes内容再关闭:
    ax.clear()
    plt.close(fig)
    
  • 优化文件IO操作:使用with上下文管理器处理输出文件,替代手动open/close,确保文件资源正确释放:
    with open(list_files[i]+'.dat','w') as output:
        # 内层循环代码
    
  • 减少重复计算:将list_ranges转换为numpy数组,提升掩码计算效率;同时避免重复计算相同的掩码条件,可将掩码提取为临时变量:
    # 先转换为numpy数组(假设ranges.dat的目标列名为'value',根据实际调整)
    range_vals = list_ranges['value'].value
    # 内层循环中
    mask = (x < range_vals[j] + 3) & (x > range_vals[j] - 3)
    x_single = x[mask]
    y_single = y[mask]
    
  • 避免过度依赖GC:移除不必要的gc.collect()调用,Python垃圾回收机制会自动处理不再引用的对象。优先确保资源被显式释放(如关闭Figure、文件),而非依赖强制GC。
  • 检查Matplotlib后端:若使用GNOME终端等桌面环境,确保Matplotlib使用的交互式后端(如TkAgg、Qt5Agg)能正确释放资源。可尝试在脚本开头添加:
    plt.switch_backend('Qt5Agg') # 或其他适合当前环境的后端
    

内容的提问来源于stack exchange,提问作者Erasmo Trentin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 06:01:04