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()
- 我一开始就正确地释放了 Xvfb 吗?
- 当它崩溃时,Xvfb 是否自动释放?
- 除了能够正确释放 Xvfb 之外,我是否应该将我的代码包装到 try ... 中?
简短的回答是,如果您的代码在您显示的位置崩溃,则不会调用 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}
在 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()
- 我一开始就正确地释放了 Xvfb 吗?
- 当它崩溃时,Xvfb 是否自动释放?
- 除了能够正确释放 Xvfb 之外,我是否应该将我的代码包装到 try ... 中?
简短的回答是,如果您的代码在您显示的位置崩溃,则不会调用 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}