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

python脚本内存泄漏,怀疑是Xvfb,python,linux,selenium,xvfb,Python,Linux,Selenium,Xvfb,在linux服务器上,我在python脚本中使用Chrome/Selenium和Xvfb。有时脚本会因为其他原因崩溃,因此,根据我在digital ocean仪表板中看到的,随着时间的推移,“Xvfb”的ram消耗最终会增加近80%。然而,ram的增加不一定是因为脚本崩溃,但可能是因为发布Xvfb的错误 下面是我与xvfb相关的内容 from pyvirtualdisplay import Display .......... display = Display(visi

在linux服务器上,我在python脚本中使用Chrome/Selenium和Xvfb。有时脚本会因为其他原因崩溃,因此,根据我在digital ocean仪表板中看到的,随着时间的推移,“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()
  • 我是否首先正确地释放了Xvfb
  • 当它崩溃时,Xvfb是否会自动释放
  • 我是否应该将代码包装到try。。。除了能够正确释放Xvfb之外

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

我认为实现您想要的最“pythonic”的方法是将
显示作为一个函数,这意味着您不需要在try/catch中包装所有代码,但您可以获得相同的好处。像这样的方法应该会奏效:

import pyvirtualdisplay

with pyvirtualdisplay.Display(visible=0, size=(800, 600)):
    // it can crash here doing other things
EDIT:在这种特殊情况下,调用stop方法很重要的原因(以及您几乎可以肯定的内存泄漏是正确的原因),是因为您的代码生成了一个子进程来充当虚拟显示。stop方法将终止此子进程,因此,如果从未调用该子进程,则该子进程将保持运行并重新租入init进程。关于这一点有更多的信息(“僵尸和孤儿进程”一节)

我能够使用以下简单的代码检查这是如何工作的:

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()
然后,在python脚本崩溃前后,我在shell中运行了
pstree-sA$(pgrep Xvfb)
(以显示Xvfb进程的进程树)

在崩溃之前,我们可以看到Xvfb进程的父进程是python(其父进程是我的shell,其父进程是我的终端仿真器等):

python脚本崩溃后,进程现在已重新租入init进程(在我的例子中,这是systemd,但在您的例子中,它可能是其他init系统)


简而言之,如果您的代码在显示的地方崩溃,则不会调用
display.sendstop()

我认为实现您想要的最“pythonic”的方法是将
显示作为一个函数,这意味着您不需要在try/catch中包装所有代码,但您可以获得相同的好处。像这样的方法应该会奏效:

import pyvirtualdisplay

with pyvirtualdisplay.Display(visible=0, size=(800, 600)):
    // it can crash here doing other things
EDIT:在这种特殊情况下,调用stop方法很重要的原因(以及您几乎可以肯定的内存泄漏是正确的原因),是因为您的代码生成了一个子进程来充当虚拟显示。stop方法将终止此子进程,因此,如果从未调用该子进程,则该子进程将保持运行并重新租入init进程。关于这一点有更多的信息(“僵尸和孤儿进程”一节)

我能够使用以下简单的代码检查这是如何工作的:

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()
然后,在python脚本崩溃前后,我在shell中运行了
pstree-sA$(pgrep Xvfb)
(以显示Xvfb进程的进程树)

在崩溃之前,我们可以看到Xvfb进程的父进程是python(其父进程是我的shell,其父进程是我的终端仿真器等):

python脚本崩溃后,进程现在已重新租入init进程(在我的例子中,这是systemd,但在您的例子中,它可能是其他init系统)


简短的回答是,如果您的代码在显示的地方崩溃,则不会调用display.sendstop()。
--假设不是这样。但是既然脚本崩溃了,操作系统不是关闭了它打开的所有处理程序吗?
简短的回答是,如果您的代码在显示的地方崩溃,则不会调用display.sendstop()。但是既然脚本崩溃了,操作系统不是关闭了它打开的所有处理程序吗?我希望我所做的编辑能更好地解释这一点。简言之,答案是否定的-PyVirtualDisplay正在创建一个子进程,即使在脚本退出后仍会保留。因此释放xfvd资源的正确方法是调用“stop()”,对吗?是的,或者使用
显示作为上下文管理器,如我在回答中所示。只要您确保始终调用
stop()
,您就不会有问题。
简短的回答是显示。如果您的代码在显示的地方崩溃,则不会调用sendstop()。
--假设没有。但是既然脚本崩溃了,操作系统不是关闭了它打开的所有处理程序吗?
简短的回答是,如果您的代码在显示的地方崩溃,则不会调用display.sendstop()。但是既然脚本崩溃了,操作系统不是关闭了它打开的所有处理程序吗?我希望我所做的编辑能更好地解释这一点。简言之,答案是否定的-PyVirtualDisplay正在创建一个子进程,即使在脚本退出后仍会保留。因此释放xfvd资源的正确方法是调用“stop()”,对吗?是的,或者使用
显示作为上下文管理器,如我在回答中所示。只要您确保始终调用
stop()
,您就会没事。