一个 Python GC 问题,虽然被解决了,但是还是不懂为什么 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
aladdindingding
V2EX    Python

一个 Python GC 问题,虽然被解决了,但是还是不懂为什么

  •  
  •   aladdindingding 2020-04-16 10:30:27 +08:00 2708 次点击
    这是一个创建于 2007 天前的主题,其中的信息可能已经有所发展或是发生改变。

    就是我们有一个 redis 的公共文件自定义了一个方法使用了 pipline,举个例子: 比如这个是一次从一个 list 一次 pop 出多个元素

    def lpopn(self, name, n): """一次 pop 多个元素""" pipe = self.pipeline() pipe.lrange(name, 0, n - 1) pipe.ltrim(name, n, -1) raw_list, is_succ = pipe.execute() return raw_list 

    之前写了一个脚本用来收集 redis 中的数据入库用了这个方法,导致脚本运行时发现了内存泄漏,然后使用内存监控工具定位到了是这个 redis.client.Pipeline 这个对象占用了大量内存,之前记得有 python 的坑说的是 如果在循环引用中的对象定义了 del,那么 python gc 不能进行回收,然后我就点进 pipeline 里面看确实是定义了 del

    class Pipeline(BasePipeline, Redis): "Pipeline for the Redis class" pass class BasePipeline(object): # 省略了其他方法 def __del__(self): try: self.reset() except Exception: pass 

    然后我就改成 脚本里面全局创建一个 pipline 对象传进这个方法,然后问题就解决了,但是不明白这个 pipeline 怎么就循环引用了呢,不知道是不是这个原因,希望有 v 友能解答一下疑惑,给点思路

    第 1 条附言    2020-04-16 13:58:18 +08:00

    使用场景之前就是一个while True脚本

    while True: redisclient. lpopn(key,pop_count) 

    后来改成在外面创建pipeline对象

    pipline = redisclient.pipeline() while True: redisclient. lpopn(key,pop_count,pipline) 
    4 条回复    2020-04-17 22:38:25 +08:00
    linw1995
        1
    linw1995  
       2020-04-16 11:31:21 +08:00
    应该是执行 self.reset() 给 pipeline 带来新的引用?导致回收不了
    aladdindingding
        2
    aladdindingding  
    OP
       2020-04-16 13:52:40 +08:00
    @linw1995 reset()应该是重置 redis 事务一些参数的 应该没有带来新的引用吧
    xiaolinjia
        3
    xiaolinjia  
       2020-04-16 15:22:53 +08:00
    我看他定义了 enter 和 exit 魔法方法。不如试试
    with self.pipeline() as pipe: ?
    不过我看他代码是一样的,大概是 del 的时候出异常了?导致 reset 没执行?
    linw1995
        4
    linw1995  
       2020-04-17 22:38:25 +08:00
    @aladdindingding 你发的代码又不全。建议用 tracemalloc 看看是不是 redis.client.Pipeline, 再用 objgraph 看看又没有被生存周期长的对象引用到。没有就应该是被 `__del__` 给复活了。https://www.python.org/dev/peps/pep-0442/
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2519 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 15:34 PVG 23:34 LAX 08:34 JFK 11:34
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86