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

Spyder运行Python代码后内存未释放的原因及解决方法

Python代码运行后内存占用居高不下的原因与解决办法

原因分析

从你的代码和现象来看,内存无法自动释放主要有这几个关键点:

  • Python垃圾回收的延迟性:Python默认用引用计数机制回收内存,但如果存在隐性引用(比如循环引用、库内部缓存),或者大对象的引用计数没降到0,垃圾回收器不会立刻清理这些内存。你最后把papers、uniques等变量设为0,只是改变了变量的指向,原有的大列表对象如果还有其他未被察觉的引用,就会一直占着内存。
  • openpyxl资源未彻底释放:虽然你调用了wb.close(),但手动关闭工作簿有时会有残留(比如sheet对象的引用没彻底清除,或者库内部的缓存没清理),导致部分内存被占用。
  • 大内存对象的累积:处理Excel时生成的field、field1、field2以及papers列表如果数据量很大,这些对象会占用大量内存,即使循环结束,若没有显式触发回收,内存不会立刻释放。

解决办法

针对这些问题,你可以从以下几个方面优化:

  1. 用with语句管理openpyxl工作簿
    with语句会自动帮你处理资源的打开和关闭,比手动调用close()更可靠,能避免资源残留。修改后的代码片段:

    if y.endswith('.xlsx'):
        # 用with自动管理工作簿生命周期
        with openpyxl.load_workbook('Persian - Copy/'+y) as wb:
            sheet = wb.active
            for z in range(2, sheet.max_row+1):
                # 原有处理逻辑不变
                id_ = str(sheet.cell(row=z, column=1).value)
                field = str(sheet.cell(row=z, column=2).value).replace('ي','ی').replace('ك','ک').split()
                field1 = str(sheet.cell(row=z, column=4).value).replace('ي','ی').replace('ك','ک').replace('None', '').split('،')
                field2 = re.sub(re.compile('<.*?>'), '', str(sheet.cell(row=z, column=3).value))
                field2 = field2.replace('ي','ی').replace('ك','ک').replace('لطفا برای مشاهده چکیده به متن کامل (PDF) مراجعه فرمایید.','').replace(' لطفا برای مشاهده چکیده به متن کامل (PDF) مراجعه فرمایید.','').replace('None', '').replace('.',' ').split()
                f = [id_, (field + field1 + field2)]
                papers.append(f)
        # 不需要手动wb.close(),with会自动处理
        sheet = None  # 显式置空sheet引用
    
  2. 显式删除大对象并触发垃圾回收
    在处理完每个Excel文件或大列表后,用del删除不再需要的对象,然后调用gc.collect()强制触发垃圾回收:

    import gc  # 先导入gc模块
    
    # 在循环处理完每个Excel文件后
    del papers
    gc.collect()
    
    # 最后处理完所有文件后
    del uniques, x_0, f
    gc.collect()
    

    注意:不要用papers = 0这种方式,而是用del papers彻底删除变量对原对象的引用,再触发GC。

  3. 优化变量作用域
    把循环内的临时变量(比如field、field1、field2)尽量限制在局部作用域,避免全局引用。比如在循环内部处理完后,可以直接把它们加入papers,不需要保留额外引用。

  4. 分块处理大文件(如果Excel数据量极大)
    如果你的Excel文件非常大,不要一次性把所有行读到内存里,可以考虑分批次读取,处理完一批就释放一批的内存,避免内存占用过高。

修改后的完整代码示例

import csv
import re
import openpyxl
import os
import gc  # 导入垃圾回收模块

papers_dir = os.listdir('Persian - Copy') #Journals
for y in papers_dir:
    papers = []
    if y.endswith('.xlsx'):
        # 使用with自动管理工作簿
        with openpyxl.load_workbook('Persian - Copy/'+y) as wb:
            sheet = wb.active
            for z in range(2, sheet.max_row+1):
                id_ = str(sheet.cell(row=z, column=1).value)
                field = str(sheet.cell(row=z, column=2).value).replace('ي','ی').replace('ك','ک').split()
                field1 = str(sheet.cell(row=z, column=4).value).replace('ي','ی').replace('ك','ک').replace('None', '').split('،')
                field2 = re.sub(re.compile('<.*?>'), '', str(sheet.cell(row=z, column=3).value))
                field2 = field2.replace('ي','ی').replace('ك','ک').replace('لطفا برای مشاهده چکیده به متن کامل (PDF) مراجعه فرمایید.','').replace(' لطفا برای مشاهده چکیده به متن کامل (PDF) مراجعه فرمایید.','').replace('None', '').replace('.',' ').split()
                f = [id_, (field + field1 + field2)]
                papers.append(f)
        sheet = None  # 清除sheet引用
        # 处理当前Excel的去重与写入
        uniques = []
        x_0 = []
        for x in papers:
            if x[0] not in x_0:
                x_0.append(x[0])
                uniques.append(x)
        with open('all.csv', 'a+', newline='', encoding='UTF-16') as un:
            writer = csv.writer(un, delimiter= '	')
            for x in uniques:
                writer.writerow(x)
        # 显式删除当前文件的大对象并回收内存
        del papers, uniques, x_0, f
        gc.collect()
    print(y)

这样修改后,每次处理完一个Excel文件就会及时释放对应的内存,不会累积到最后导致内存占用居高不下。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:23:35