如何在 gst_object_unref() 后处理泄漏的文件描述符问题?

6

我有一个自定义管道,在gstreamer缩写中大致如下:

gst-launch-1.0 rtspsrc location=rtsp://<url-for-stream> ! rtph264depay ! h264parse ! imxvpudec ! *any-sink*
  • 任何音视频渲染器都可以,可以是fakesink、imxipusink或其他(我使用Freescale imx插件的imx6平台)。我可以输出到任何我想要的渲染器中,但问题却是相同的。

在gst-launch-1.0中,这种类型的管道可以正常工作,因为它不需要正确地清理自己,但我需要在我的C++应用程序中使用直接的GST API。这意味着我使用myPipeline = gst_pipeline_new("custom-pipeline"),然后按名称分配每个插件、链接它们并运行管道。之后,我需要停止管道并调用gst_object_unref(myPipeline)。在执行此操作时,我观察到有一些文件描述符被留下来。我之后需要再次启动管道,所以泄漏正在累加。这个操作需要经常进行,而泄漏的描述符会导致异常:

GLib-ERROR **: Creating pipes for GWakeup: Too many open files

我可以使用lsof检测打开的文件...

lsof +E -aUc myGstApplication        
lsof: netlink UNIX socket msg peer info error
COMMAND    PID USER   FD   TYPE     DEVICE SIZE/OFF     NODE NAME
myGstApplication 5943 root    3u  unix 0xabfb6c00      0t0 11200335 type=STREAM
myGstApplication 5943 root   11u  unix 0xd9d47180      0t0 11207020 type=STREAM

...根据运行时间的长短,可能会有更多...

myGstApplication 5943 root   50u  unix 0xabe99080      0t0 11211987 type=STREAM

每当我使用unref()并重新构建pipeline时,似乎会得到两个新的“type=STREAM”文件描述符。

在lsof中看到描述符很好,但我不知道如何跟踪代码中这些文件的来源。例如,lsof输出是否能给我提供更好的调试信息? 我该如何追踪这些泄漏的真正来源并停止它们?一定有更好的方法...对吧?

我怀疑gstreamer pipeline元素中的rtspsrc与此有关,但rtspsrc本身是一个底层的gstreamer实现(udpsrcs、demuxers等等)。我不确定它是否是rtspsrc内部的错误,因为很多人似乎都在使用它而没有重现相同的问题。难道是我的应用程序代码中做了什么非常不明显的事情导致了这种行为吗?

非常感谢任何帮助!谢谢!


你尝试过使用GST_DEBUG选项吗?它可以为管道中的每个元素提供调试相关信息。 - gst
是的,我只看到这个:0:00:57.383872340 6101 0x69b34fb0 警告 GST_PADS gstpad.c:3990:gst_pad_peer_query:<recv_rtp_sink_1:proxypad36> 无法发送粘性事件 0:00:57.389069340 6101 0x69b34830 警告 GST_PADS gstpad.c:3990:gst_pad_peer_query:<udpsrc14:src> 无法发送粘性事件 - adowdy
2
我曾经遇到过完全相同的情况。我的问题是在释放管道时没有移除总线监视器 - 记得在添加总线监视器之前执行gst_bus_remove_watch - Raber
1个回答

4

研究充分且有趣的问题!

根据lsof输出,泄漏的文件描述符似乎来自于socketpair系统调用。您可以使用strace确认:

strace -fe socketpair myGstApplication

在此之后,您可以省略对socketpair系统调用的过滤,并查看完整的strace输出,试图理解这些FD用于什么。我尝试了使用gst-launch-1.0进行此操作,但结果并不确定。这些FD似乎在两端都被设置为只读,并且从未传输任何内容...因此它们必须仅用于同一应用程序的多个线程/子进程之间的控制/协调。

下一个尝试将是gdb:

gdb -ex 'break socketpair' -ex run myGstApplication

当它在断点处停止时,使用bt命令查看堆栈跟踪。安装gstreamer的调试软件包可能是获取更易读的堆栈跟踪的好方法。

希望有所帮助 :)


谢谢Micha——我已经开始尝试使用strace了,但是你给了我更多的上下文来玩耍。我会再跟进的! - adowdy
我已经确定了一个调用socketpair的gst函数存在泄漏。在GDB中显示,调用gst_poll_new_timer()似乎是创建socketpair的函数,但我一直没有成功地获取到堆栈跟踪:Thread 1 hit Breakpoint 1, 0x6b07b0bc in gst_poll_new_timer () from target:/usr/lib/libgstreamer-1.0.so.0 (gdb) bt #0 0x6b07b0bc in gst_poll_new_timer () from target:/usr/lib/libgstreamer-1.0.so.0 #1 0x6b096960 in ?? () from target:/usr/lib/libgstreamer-1.0.so.0 Backtrace stopped: previous frame identical to this frame (corrupt stack?)...使用调试包,据我所知。 - adowdy
忽略我之前的评论 - 我需要根据与 "yocto" 互动来重新配置我的 gdb 环境,因为如果不按照他们的方式进行操作,我认为我会得到错误的信息。仍在朝着可读的堆栈跟踪努力...这真是一种糟糕的痛苦。 - adowdy
仅为后人留下的最后一次更新 - 这种方法对我来说足够好,可以追踪问题的根源 - gst_element_get_bus(my_pipeline) 的使用在引用计数机制中没有正确地减少。拆除管道时,我还必须完善代码,通过gst_object_unref(GST_OBJECT(m_bus))在创建新管道时减少总线引用。 - adowdy
嗨@adowdy,我遇到了类似的问题...你能否发布一些有关你所做的代码更改的详细信息?这会对我很有帮助。谢谢! - textral

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接