python 脚本中的内存泄漏,怀疑是 Xvfb

Memory leaks in a python script, Xvfb is suspected

在 linux 服务器上,我在 python 脚本中使用 Chrome/Selenium 和 Xvfb。有时脚本会因其他原因崩溃,因此,根据我在数字海洋仪表板中看到的情况,随着时间的推移,"Xvfb" 的 ram 消耗最终增加了近 80%。但是,ram增加不一定是因为脚本崩溃,而是可能是因为一般释放Xvfb的错误。

这是我所掌握的与 xvfb 相关的内容

    from pyvirtualdisplay import Display
    ..........
    display = Display(visible=0, size=(800, 600))
    display.start()


    //it can crash here doing other things

    display.sendstop()

简短的回答是,如果您的代码在您显示的位置崩溃,则不会调用 display.sendstop()

我认为最 'pythonic' 实现您想要的方法是将 Display 用作 context manager,这意味着您不需要包装所有代码在 try/catch 但你得到同样的好处。这样的事情应该有效:

import pyvirtualdisplay

with pyvirtualdisplay.Display(visible=0, size=(800, 600)):
    // it can crash here doing other things

编辑:在这种特殊情况下调用 stop 方法很重要的原因(以及为什么您几乎肯定对内存泄漏是正确的)是因为您的代码正在生成 Xvfb subprocess to act as the virtual display. The stop method kills this subprocess and so if it is never called the subprocess remains running & is reparented onto the init process. There is some more information on this here(第 'Zombie and Orphan Processes').

我能够使用这段简单的代码来检查它是如何工作的:

import time
from pyvirtualdisplay import Display

display = Display(visible=0, size=(800, 600))
display.start()

print('About to sleep')
time.sleep(20)

raise Exception('Oh noes!')

display.stop()

我然后 运行 pstree -sA $(pgrep Xvfb) 在我的 shell (显示 Xvfb 进程的进程树)之前和之后 python 脚本崩溃。

崩溃前我们可以看到Xvfb进程的父进程是python(它的父进程是我的shell,它的父进程是我的终端模拟器等等):

systemd---xfce4-terminal---zsh---python---Xvfb-+-{llvmpipe-0}
                                               |-{llvmpipe-1}
                                               |-{llvmpipe-2}
                                               `-{llvmpipe-3}

在 python 脚本崩溃后,该进程现在已重新定位到 init 进程(在我的情况下,这是 systemd,但在您的情况下,它可能是其他初始化系统)。

systemd---Xvfb-+-{llvmpipe-0}
               |-{llvmpipe-1}
               |-{llvmpipe-2}
               `-{llvmpipe-3}