使用多处理重复启动 Gtk 应用程序.进程(或者:如何在python中沙箱Gtk)



Intro

:我需要(内存)在python中对Gtk/Gstreamer应用程序进行沙箱处理并定期重新启动它。

:我在库(gstreamer)中遇到内存泄漏,我将其用于从相机获取数据的更大代码块。为了避免争论,我试图解决这个问题一段时间,但不能。我需要相机数据,所以我决定尝试破解一个解决方案,这应该是手动黑客的自动化,这将是定期在内存填满之前重新启动软件。

但是,我根本不习惯 Gtk,我对 python 内存管理知之甚少。因此,我遇到了问题。

设置

所以现在,程序是使用 Gtk3 用 python 编写的。我有一个myPythonObjectWithGtkStuff,它本质上是 http://bazaar.launchpad.net/~jderose/+junk/gst-examples/view/head:/webcam-1.0 的更花哨的版本。 但尤其是__init__()run()中的 Gtk 部分是相同的。(请注意这条线 http://bazaar.launchpad.net/~jderose/+junk/gst-examples/view/head:/webcam-1.0#L51 以及on_sync_message()函数,这可能是一个红鲱鱼,但它们处理使用 xid 手柄将 gstreamer 流定向到 Gtk 绘图区域)

问题/解决方案 1

我想象它的工作方式是创建整个对象,在 while 循环中保存所有代码。然后在某个时间点window.destroy()从 Gtk 主循环中调用。它将返回到 while 循环,然后创建另一个对象,依此类推。

# shitty hack to restart the Gtk application once it got destroyed
while(1):
    startVC(args)

def startVC(args):    
    mainloop = GObject.MainLoop()
    obj = myPythonObjectWithGtkStuff(args)
    obj.run()
    del obj

目前为止,一切都好。如果我按照上面写的去做,一切正常。此解决方案的问题在于它不会释放obj的内存。(我认为主要是内存泄漏的东西仍然存在,我不确定)。

编辑:

在我调用 window.destroy() 的那一刻,Gtk 窗口关闭了,我可以看到内存使用量下降到某个稳定的基本值。一旦 Gtk 再次启动,内存使用量将返回到以前的操作内存使用量加上一些与内存泄漏产生的量相对应的额外内存。

问题/解决方案 2

现在我想我可以在一个进程中启动 Gtk,然后在它返回时终止它并启动一个新进程。

while(1):
    p = Process(target=startVC, args=(args,))            
    p.start()
    p.join()        
    p.terminate()

这里的问题是它第一次启动得很好,但是一旦第一个进程返回并且循环启动第二个进程,我在调用self.window = Gtk.Window()__init()__() myPythonObjectWithGtkStuff时出现以下错误:

Gdk-WARNING **: captureVideo.py: Fatal IO error 11 (Resource temporarily unavailable) on X server :0.

Gdk-WARNING **: captureVideo.py: Fatal IO error 0 (Success) on X server :0.

怎么办?

我现在需要的是解决这两个问题中的任何一个。如何确保第一个解决方案的对象从内存中完全删除,或者如何避免解决方案 2 的 X 服务器错误。

可能是调用我self.window.destroy() obj不足以杀死所有 Gtk 的东西。这是关闭 Gtk 应用程序的正确方法吗?

我现在最终做了类似这个单独的小脚本

# file: keepAliveWrapper.py
import sys
import subprocess as sp
if __name__ == "__main__":
    args = sys.argv[1:]
    while(1):                
        print("calling: python {args}".format(args=' '.join(args)))
        p = sp.Popen("python {args}".format(args=' '.join(args)),
                     shell=True, stdout=sp.PIPE, stderr=sp.STDOUT)
        output =  p.communicate()[0]

它将它管理的脚本及其命令行参数一起作为参数。所以基本上不是在命令行中调用说python gtkProgram.py -d /home/peter/test -e 10,而是现在运行python keepAliveWrapper.py gtkProgram.py -d /home/peter/test -e 10

如果有人有更聪明的想法,请告诉我。

PS:供将来参考:p.communication() 允许解析保持活动状态的程序的输出。也就是说,通过这种方式,可以传递"信号"来决定是否打破while循环。

最新更新