跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 请教 Python 多线程内存不释放怎么排查
未分類
10 10 月 2020

请教 Python 多线程内存不释放怎么排查

请教 Python 多线程内存不释放怎么排查

資深大佬 : r150r 2

新手写了一个多线程的爬虫,所有线程都执行完了,但是一直占着 1.5GB 的内存(任务数越多不释放的内存越多) 不知道怎么排查哪里出问题,pympler 看不太懂问题到底出在哪里,请教该如何正确的排查问题

执行多线程函数的代码:

    def mainfunc(tasknum, thread):         tr = tracker.SummaryTracker()         tr.print_diff()         list = []         for i in range(tasknum):             list.append(str(i))         pool = threadpool.ThreadPool(thread)         requests = threadpool.makeRequests(childfunc, list)         for req in requests:             pool.putRequest(req)         pool.wait()         tr.print_diff() 

tr.print_diff()打印的内容

初始化:

                     types |   # objects |   total size ========================== | =========== | ============                       list |        3741 |    350.84 KB                        str |        3739 |    260.01 KB                        int |         673 |     18.40 KB                       dict |           2 |    352     B                      tuple |           4 |    256     B                       code |           1 |    144     B      function (store_info) |           1 |    136     B                       cell |           2 |     96     B   functools._lru_list_elem |           1 |     80     B                     method |          -1 |    -64     B 

所有线程结束后:

                                types |   # objects |   total size ===================================== | =========== | ============                                  dict |      202860 |     43.69 MB                                  list |      100169 |      8.47 MB                                   str |      102446 |      5.62 MB                threadpool.WorkRequest |      100000 |      5.34 MB                                   int |      100836 |      3.08 MB                    _io.BufferedReader |         294 |      2.35 MB                                 tuple |        1480 |     93.30 KB                                  type |          76 |     85.98 KB                                  code |         572 |     80.57 KB                                 bytes |        1219 |     51.49 KB                                   set |          32 |     43.50 KB                         socket.socket |         294 |     27.56 KB        pymysql.connections.Connection |         294 |     16.08 KB                       socket.SocketIO |         294 |     16.08 KB   DBUtils.SteadyDB.SteadyDBConnection |         294 |     16.08 KB 

大佬有話說 (24)

  • 資深大佬 : scriptB0y

    线程池里面的任务,检查一下所有的函数最后都有 return,没有的加一下,再试试。

  • 主 資深大佬 : r150r

    @scriptB0y 所有的函数都有 return 了

  • 資深大佬 : wevsty

    检查有没有循环引用数据结构的问题。

  • 資深大佬 : Hstar

    把你代码复制跑了一遍,是你代码里 requests 这个变量的问题,这个变量缓存了你所有任务的引用,只要你的 mainfunc 函数不结束这些引用就不会消失。
    你可以在 mainfunc 外面套一层函数再打印 tr.print_diff()看看,会发现内存占用消失了。
    也可以把
    for req in requests:
    pool.putRequest(req)
    改成
    while requests:
    pool.putRequest(requests.pop())

  • 主 資深大佬 : r150r

    @Hstar 谢谢解答!改成 requests.pop()后打印 tr.print_diff(),list 和 dict 明显少了。不过 htop 显示 1.5G 内存还是没释放,除非这个 mainfunc 结束,看来是 childfunc 的问题。

  • 資深大佬 : byaiu

    内存分配是有状态的

  • 資深大佬 : superrichman

    爬虫,你是不是用了 beautiful soup ?这个用完了要手动 decompose 一下,不然内存会爆炸

  • 資深大佬 : zhuangzhuang1988

    不好查
    国内的 python 核心开发着也扯到了 https://pythonhunter.org/episodes/9

  • 資深大佬 : noobsheldon

    把这个 mainfunc 放入一个子进程执行, 子进程结束,让系统自己回收内存呢?

  • 資深大佬 : mumbler

    “del 变量名” 可以手动释放内存

  • 資深大佬 : cloudyplain

    1.threadpool 改为全局? 2.换 tcmalloc

  • 資深大佬 : cheng6563

    不会 python
    现代的 gc 一般就算回收了内存也不会把内存还给操作系统
    可以考虑新启一个进程,操作完结束进程

  • 資深大佬 : chenqh

    req 是什么东西?

  • 主 資深大佬 : r150r

    @superrichman 没有使用 beautiful soup

  • 資深大佬 : wangritian

    变量释放后,可能仅仅被 py 标记为垃圾,并没有归还操作系统,下次你再申请变量优先从垃圾堆里找
    开子进程用完销毁是最可行的方案,另外找找有没有像 go 的 debug.FreeOSMemory()这种强制归还操作系统的函数

  • 主 資深大佬 : r150r

    @noobsheldon 目前是把 mainfunc 放入子进程,分段每 100000 个任务执行 1 次
    可目标站的 tid 越高,需要解析的资源就越多,每 100000 个任务需要的内存也就越来越高。
    现在 100000 个任务要 26GB 内存了,只能手动调整任务数

  • 主 資深大佬 : r150r

    已更新可以复现问题的最小化代码

  • 資深大佬 : chenqh

    不用 threadpool 试试?

  • 主 資深大佬 : r150r

    @wangritian 只保持 50 个线程 get 一个相同链接,内存使用量却跟随任务数量无止尽增长,请问这是没有被标记为垃圾,所以无法回收吗?

  • 主 資深大佬 : r150r

    @chenqh 之前试过 multiprocessing.dummy 也不释放

  • 主 資深大佬 : r150r

    python 标记变量为垃圾而不释放有什么条件吗?
    如果把代码里的 session.get 替换成 str = ‘ ‘ * (500 * 1024 * 1024),使用的内存会马上就归还给系统,是 requests 的问题吗

  • 資深大佬 : mywaiting

    之前遇到过类似的问题,把 requests 的 timeout 调小一点吧 timeout=(5, 10) 试试

  • 資深大佬 : changePro

    这个问题我今晚研究了下,Py 自己管理内存

    “`
    str = ‘ ‘ * (500 * 1024 * 1024)
    “`

    这段代码有可能是在栈上面的,用完了 frame 就没了,内存自然释放

    但是

    “`
    res = s.get(url, timeout=(5, 60))
    “`

    有可能是在堆上面的,GC 回收的话,应该有内在策略,找时间可以分析分析内存布局

  • 資深大佬 : HappyTrail

    https 改成 http 试试看 – –

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具