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

多线程Python项目疑似内存泄漏问题排查求助

内存异常增长的原因分析与排查建议

内存异常增长大概率是Python代码逻辑缺陷和unix程序solve-field异常行为共同作用的结果,以下是具体分析和排查方向:

一、Python代码层面的潜在问题

  1. 线程池重复创建导致资源残留
    在Controller.start()的while True循环内,每次迭代都会新建ThreadPoolExecutor实例。虽然with语句会自动关闭executor,但频繁创建销毁线程池可能导致线程资源未完全释放,长期运行后积累内存占用。

  2. subprocess输出未限制引发内存暴涨
    AM.test_func()中使用capture_output=True会将solve-field的所有标准输出、错误输出全部读取到Python内存中。如果无效文件触发该程序输出巨量错误日志(比如GB级内容),会直接导致Python进程内存飙升至3.5G。

  3. 方法调用参数错误引发无效异常
    AM.start()方法定义需要fname参数,但Controller._start_func()中调用AM(f"{newFname}").start()时未传递该参数,会触发TypeError。虽然被try/except捕获返回1,但异常处理过程可能产生未清理的临时对象,长期积累增加内存占用。此外AM.__init__接收fname参数却未保存,属于冗余逻辑。

  4. multiprocessing队列的潜在积压风险
    使用multiprocessing.Manager()创建的队列q,如果任务处理速度跟不上队列写入速度,会积压大量文件路径,间接增加内存占用(需结合实际任务量验证)。

二、unix程序solve-field的可能问题

  1. 错误场景下的巨量输出
    当配置文件缺失或处理无效文件时,solve-field可能进入异常逻辑,产生海量错误输出。这些输出被Python通过capture_output=True读入内存后,直接导致进程内存暴涨。

  2. 程序自身内存泄漏
    如果solve-field在处理文件(尤其是无效文件)时存在内存泄漏,虽然子进程结束后系统会回收资源,但多次调用后可能导致系统级内存占用上升;若程序在错误场景下临时申请大量内存未释放,也会间接推高Python进程的内存统计。

三、排查与修复步骤

  1. 验证subprocess输出的影响
    临时修改AM.test_func(),丢弃所有输出:

    p = subprocess.run(c, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    

    观察错误场景下内存是否还会飙升。若内存恢复正常,说明是输出内容过多导致的问题。

  2. 复用线程池减少资源消耗
    将ThreadPoolExecutor初始化移到循环外部,避免频繁创建销毁:

    def start(self):
        event_handler = Handler()
        observer = watchdog.observers.Observer()
        observer.schedule(event_handler, path=cfg.paths["ipath"], recursive=True)
        observer.start()
        
        try:
            with concurrent.futures.ThreadPoolExecutor(max_workers=cfg.workers) as executor:
                while True:
                    time.sleep(1)
                    futures = {}
                    while not q.empty():
                        newFname = q.get()
                        futures_to_work = executor.submit(self._start_func, newFname)
                        futures[futures_to_work] = newFname
    
                    for future in concurrent.futures.as_completed(futures):
                        name = futures.pop(future)
                        print(f"{name} completed")
                    
        except KeyboardInterrupt:
            observer.stop()
        observer.join()
    

    长期运行后观察内存是否仍持续增长至200-300M。

  3. 修复参数传递错误
    修正AM类的参数逻辑:

    class AM():
        def __init__(self, fname):
            self.fname = fname
        
        def test_func(self):
            c = f"solve-field {self.fname}".split(" ")
            p = subprocess.run(c, capture_output=True, text=True)
    
            out, err = p.stdout, p.stderr
            if out:
                print(out)
            if err:
                print(err)
                return 1
            return 0
    
        def start(self):
            res = self.test_func()
            return res
    

    避免不必要的异常处理开销。

  4. 排查solve-field自身问题
    直接在命令行手动运行solve-field处理无效文件或模拟配置缺失场景,用top或ps观察该进程的内存占用。如果进程在错误场景下内存占用极高,说明程序自身存在问题,需查看astrometry.net相关文档或提交issue。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 02:21:01