gsteramer appsink(Python绑定)导致内存泄漏

xienkqul  于 2023-03-21  发布在  Python
关注(0)|答案(3)|浏览(332)

我正在尝试使用appsink构建管道,它占用了大量内存:

#!/usr/bin/env python

import sys

import gi

gi.require_version('Gst', '1.0')
from gi.repository import GObject, Gst

def main():
    GObject.threads_init()
    Gst.init(None)
    # pipeline = Gst.parse_launch('fakesrc ! fakesink')
    pipeline = Gst.parse_launch('fakesrc ! appsink')

    loop = GObject.MainLoop()

    pipeline.set_state(Gst.State.PLAYING)
    try:
        loop.run()
    except:
        pass

    pipeline.set_state(Gst.State.NULL)

if __name__ == '__main__':
    sys.exit(main())

即使没有设置连接,内存也在不断增加。我尝试使用sink.connect("new-sample", handler, sink)连接一个函数-它也会泄漏内存。还尝试向总线添加处理程序(在某处读到gst可能会将未发送到python的消息排队并永久保留它们)-也没有帮助。
我需要在某个地方释放内存吗?我在C代码中发现了对gst_object_unref的调用,但我不确定是否应该在Python代码中使用unref。
此外,简单管道'fakesrc ! fakesink'不会泄漏内存。
该脚本在Docker内部运行(不确定这是否重要,不幸的是,我无法在Docker外部进行测试):

FROM python:3.6
ENV PYTHONUNBUFFERED 1
RUN mkdir -p /code
WORKDIR /code
ADD Pipfile Pipfile.lock /code/
RUN apt-get update && apt-get install -y software-properties-common cmake \
    gobject-introspection libgirepository1.0-dev libcairo2-dev \
    libgstreamer1.0-0 gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \
    gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc gstreamer1.0-tools \
    python-gst-1.0
RUN pip install pipenv && pipenv install --system
ADD . /code/
WORKDIR /code/src
EXPOSE 8181
CMD python main.py
0aydgbwb

0aydgbwb1#

Appsink有一个队列,它存储传入的样本。默认情况下,此大小是无限的。您可以通过appsink的max-buffersdrop属性控制此大小,以便它不会无限增长。
但您实际上需要做的是主动地将这些样本从appsink中拉出来并进行处理--或者至少只是丢弃它们。
new-sample信号是一个很好的开始。如果触发了这个信号,一个新的样本就已经到达并准备好被处理了。我在这里记不起Python了,但是你想调用appsink对象的pull_sample方法来从appsink获得样本的所有权。一旦你离开了作用域,样本应该会被正确地释放-我猜。
编辑:确保信号被发出。有一个appsink属性emit-signals,默认情况下是关闭的。但我通常做C的东西,所以我不确定Python是否会触发一些开关,所以它可以开箱即用。

e4eetjau

e4eetjau2#

好吧,解决方案(至少是hotfix)很简单:手动调用gc.collect()
我不太清楚为什么它没有自动调用(或释放),但简单地在每个sink处理程序上调用gc.collect()就解决了这个问题。在每个帧上调用gc并不是超级有效的,当我有空闲时间的时候,我一定会做一些研究。
通过重写Java(它也会占用大量内存)发现了解决方案,但在Java中,您可以指定-Xmx,这会减少JVM可用的内存量

r8xiu3jd

r8xiu3jd3#

对我来说,最大的问题是MappingInfo
如果您在应用程序中的任何位置收到Gst.Buffer并需要数据:
success, map_info = buffer.map(Gst.MapFlags.READ)
现在您可以轻松地接收缓冲区数据:
data = map_info.data
如果您忘记了buffer.unmap(map_info),Map将继续增长而不会被取消引用,并且您的内存将在几秒钟内完全填满。

相关问题