Spyder运行Python代码后内存未释放的原因及解决方法
Python代码运行后内存占用居高不下的原因与解决办法
原因分析
从你的代码和现象来看,内存无法自动释放主要有这几个关键点:
- Python垃圾回收的延迟性:Python默认用引用计数机制回收内存,但如果存在隐性引用(比如循环引用、库内部缓存),或者大对象的引用计数没降到0,垃圾回收器不会立刻清理这些内存。你最后把
papers、uniques等变量设为0,只是改变了变量的指向,原有的大列表对象如果还有其他未被察觉的引用,就会一直占着内存。 - openpyxl资源未彻底释放:虽然你调用了
wb.close(),但手动关闭工作簿有时会有残留(比如sheet对象的引用没彻底清除,或者库内部的缓存没清理),导致部分内存被占用。 - 大内存对象的累积:处理Excel时生成的
field、field1、field2以及papers列表如果数据量很大,这些对象会占用大量内存,即使循环结束,若没有显式触发回收,内存不会立刻释放。
解决办法
针对这些问题,你可以从以下几个方面优化:
用
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引用显式删除大对象并触发垃圾回收
在处理完每个Excel文件或大列表后,用del删除不再需要的对象,然后调用gc.collect()强制触发垃圾回收:import gc # 先导入gc模块 # 在循环处理完每个Excel文件后 del papers gc.collect() # 最后处理完所有文件后 del uniques, x_0, f gc.collect()注意:不要用
papers = 0这种方式,而是用del papers彻底删除变量对原对象的引用,再触发GC。优化变量作用域
把循环内的临时变量(比如field、field1、field2)尽量限制在局部作用域,避免全局引用。比如在循环内部处理完后,可以直接把它们加入papers,不需要保留额外引用。分块处理大文件(如果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
相关产品推荐
相关产品推荐

