PBS vmem超限:150万面要素多进程相交任务如何定位内存溢出位置
内存溢出原因定位
- 主进程预生成全量参数占用过高:150万个带几何对象的参数元组全部存入
args列表后,本身就会占用极大内存,还没开始执行子进程任务主进程可能就已经占用了数G内存。 - 任务队列重复拷贝大对象:
starmap会把所有任务序列化后传入共享任务队列,如果你传递的dgrid、网格参数是大对象,每个任务都会独立拷贝一份,内存占用会直接翻倍甚至翻数倍。 - 子进程内存累积泄漏:如果
calculate函数内的中间几何对象没有被及时回收,或者返回值保留了大量无用字段,子进程处理的任务越多,内存占用会持续累积不释放。 - 进程数量过多叠加内存占用:
Pool默认会启动和CPU核心数相等的子进程,如果每个子进程峰值内存占用1G,16核就会占到16G,很容易触碰到PBS队列的vmem限制。
内存超限定位方法
- 单进程压测定位:先注释多进程逻辑,改成单进程循环处理前1000个polygon,安装
memory-profiler库,用@profile装饰器修饰calculate函数和主逻辑,执行python -m memory_profiler your_script.py即可直接输出每一行代码的内存占用变化,精准定位占内存最高的代码段。 - 主进程参数内存监控:循环生成
args时,每生成1万条就打印一次主进程的RSS内存,确认是不是攒全量参数阶段就已经触发内存超限。 - 子进程分批次打印内存:把你现有的psutil监控逻辑改成每处理100个polygon打印一次当前子进程PID、内存占用和当前处理的polygon index,即可确认是处理到第几个任务时内存开始飙升,区分是特定polygon的问题还是累积泄漏。
- PBS作业内存匹配:在PBS提交脚本中每隔30秒输出一次
qstat -f $PBS_JOBID的vmem统计值,同时主进程打印当前已处理的polygon数量,两者对应即可精准定位到内存触达阈值的处理阶段。
内存控制优化方案
- 分批次提交任务,不攒全量参数:每次只生成小批量任务,处理完直接释放该批次的参数内存,示例代码如下:
import gc import multiprocessing as mp batch_size = 2000 # 可根据内存情况调整,批次越小主进程内存占用越低 process_num = 4 # 手动指定进程数,根据单进程峰值内存算好总占用不要超过PBS限制 pool = mp.Pool(processes=process_num) args = [] for index, pol in shapefile.iterrows(): ylat = lat_gridlimits xlon = lon_gridlimits args.append((dgrid, ylat, xlon, pol, index)) if len(args) >= batch_size: pool.starmap(calculate, args) args.clear() gc.collect() # 手动触发回收主进程无用对象 # 处理剩余不足一批的任务 if args: pool.starmap(calculate, args) pool.close() pool.join()
- 只读大对象不用重复传参:如果
dgrid、网格参数是所有任务共享的只读对象,不要放到args里每个任务传一遍,可通过全局变量或者multiprocessing.Manager共享内存的方式传递,避免重复拷贝占用内存。 calculate函数内部优化:处理完相交运算后及时删除不需要的中间几何对象,每处理几十条任务手动调用一次gc.collect(),返回值只保留需要的统计字段,不要返回完整polygon对象。
内容的提问来源于stack exchange,提问作者Marylin UH
相关产品推荐
相关产品推荐

