Python3中sys.exit()无法终止子进程及内存占用异常求助
嘿,我来帮你拆解下为啥Python3里这个子进程退不掉,还有内存泄漏的问题~
为啥子进程没法终止?
核心原因是日志线程在拖后腿:
你在backUp里启动的self.logger是个普通线程(Python默认线程都是非守护线程),在Python3中,当子进程调用sys.exit()时,只会终止子进程的主线程,但子进程会一直等着所有非守护线程跑完才会真正退出。所以不是sys.exit()没用,是日志线程没结束,导致整个子进程没法退出。
至于Python2里能正常运行,大概率是之前的日志线程在Python2里有隐含的退出条件,或者线程逻辑在Python2下能自然结束,但迁移到Python3后这个差异暴露出来了。
为啥内存会被耗尽?
每次引脚触发下降沿,你都会调用Process(target=self.backUp).start()创建新进程,但之前的backup进程因为日志线程的原因根本没退出,这些“僵尸”进程会一直占着内存,次数多了内存自然就被耗干了。
怎么解决?
给你三个实用方案,按需选:
1. 把日志线程改成守护线程
这是最简单的办法,只要在启动日志线程前,把它的daemon属性设为True。守护线程的特点是:只要主进程/主线程退出,它会被强制终止,不会拖后腿。
def backUp(self): """ 用于创建备份反馈日志。@return: None. """ if product is not None: self.logger.__init__() # 设为守护线程,主线程退出时它会跟着结束 self.logger.daemon = True self.logger.start() # do some stuff sys.exit()
2. 手动停止日志线程再退出
如果你的日志必须写完所有内容才能退出,不能用守护线程,那就在sys.exit()前,主动让日志线程停止,并等待它结束。比如给你的日志线程类加个停止方法:
# 假设你的logger是继承threading.Thread的类 class LoggerThread(threading.Thread): def __init__(self): super().__init__() # 加个标记控制线程循环 self._should_run = True def run(self): # 原来的日志逻辑改成循环,用_should_run控制 while self._should_run: # 执行日志写入操作 pass def stop(self): # 标记线程停止 self._should_run = False
然后在backUp里调用:
def backUp(self): """ 用于创建备份反馈日志。@return: None. """ if product is not None: self.logger.__init__() self.logger.start() # do some stuff # 先停止日志线程,等它把剩余日志写完 self.logger.stop() self.logger.join() # 等待线程结束 sys.exit()
3. 避免重复创建进程
加个标志位,每次触发引脚事件时,先检查有没有正在运行的backup进程,如果有就不创建新的,这样就不会堆进程了:
# 先在类的__init__里加个进程实例变量 def __init__(self): # 其他初始化代码... self.backup_process = None def pin_event_down(self): """ 用于创建产品引脚事件。@return: None. """ # do some stuff # 检查进程是否存在且存活,只有不存在/已结束才创建新的 if not (self.backup_process and self.backup_process.is_alive()): self.backup_process = Process(target=self.backUp) self.backup_process.start() # do some stuff
这样三个方案结合起来,应该就能解决你的问题啦~
内容的提问来源于stack exchange,提问作者Jasper

