scikit-fuzzy循环调用时函数内部局部对象未销毁导致内存泄漏问题咨询
问题原因分析
- 循环引用+自定义析构方法导致GC失效:你遇到的内存泄漏是scikit-fuzzy旧版本的已知问题,核心出在
ctrl.Rule、ctrl.ControlSystem两个类的实现上:这两个类互相持有对方的引用(Rule会绑定到所属的ControlSystem,ControlSystem存储所有Rule实例),同时早期版本的类定义中带有自定义的__del__析构方法。CPython的垃圾回收机制无法处理带有__del__方法的循环引用链,这部分对象的引用计数永远不会降到0,也不会被GC主动回收,每调用一次base_example就会残留一批对象在内存中。 - 你可以导入
gc模块后打印gc.garbage验证,跑几轮循环后会看到大量无法被回收的Rule、ControlSystem实例。
修复方案
- 升级scikit-fuzzy到最新版本:官方在0.4.2及之后的版本已经修复了这个问题,移除了导致GC阻塞的
__del__方法,优化了对象引用结构,升级后重复调用不会再出现内存持续上涨的情况。 - 临时兼容方案(无法升级版本时使用):如果必须使用旧版本,不要在循环内部重复创建
ControlSystem和Rule实例,把这部分逻辑提到循环外面全局初始化,每次循环仅复用同一个ControlSystemSimulation实例即可,示例如下:
from skfuzzy import control as ctrl import skfuzzy as fuzz import numpy as np from pympler import tracker # 全局初始化一次规则和控制系统 quality = ctrl.Antecedent(np.arange(0, 11, 1), 'quality') service = ctrl.Antecedent(np.arange(0, 11, 1), 'service') tip = ctrl.Consequent(np.arange(0, 26, 1), 'tip') quality.automf(3) service.automf(3) tip['low'] = fuzz.trimf(tip.universe, [0, 0, 13]) tip['medium'] = fuzz.trimf(tip.universe, [0, 13, 25]) tip['high'] = fuzz.trimf(tip.universe, [13, 25, 25]) rule1 = ctrl.Rule(quality['poor'] | service['poor'], tip['low']) rule2 = ctrl.Rule(service['average'], tip['medium']) rule3 = ctrl.Rule(service['good'] | quality['good'], tip['high']) tipping_ctrl = ctrl.ControlSystem([rule1, rule2, rule3]) if __name__ == '__main__': tr = tracker.SummaryTracker() # 可全局复用同一个模拟实例,每次计算前调用reset()清空历史数据 tipping = ctrl.ControlSystemSimulation(tipping_ctrl) for i in range(100000): tipping.reset() tipping.input['quality'] = 6.5 tipping.input['service'] = 9.8 tipping.compute() if i%500==0: print('Iteration ',i) tr.print_diff()
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

