Hi everyone,
I’m running into a serious issue when using Streamlit with OpenCV to display RTSP video streams. The memory usage of the Streamlit process grows steadily — about 100 MB per minute — and it never goes down, even after stopping the stream.
Some key observations:
-
If I display the same RTSP stream with
cv2.imshow(), there is no memory leak. -
Multiprocessing is not the cause — I tested a minimal version with just OpenCV and Streamlit.
-
The issue seems to appear specifically when calling
st.image/box.image(...).
Example code (close to real usage, but simplified):
# app.py
import cv2
import time
import streamlit as st
from typing import Optional
class RTSPApp:
def __init__(self):
st.set_page_config(page_title="RTSP Memory Leak Test", layout="wide")
st.title("RTSP Memory Leak Test")
st.session_state.setdefault("rtsp_started", False)
st.session_state.setdefault("cap", None)
st.session_state.setdefault("last_url", "")
def run(self):
url = st.text_input("RTSP URL", "rtsp://...")
start = st.button("▶️ Start")
stop = st.button("⏹️ Stop")
if start:
self.start_stream(url)
if stop:
self.stop_stream()
if st.session_state["rtsp_started"]:
self.loop()
def start_stream(self, url: str):
url = (url or "").strip()
if not url:
st.warning("URL is empty.")
return
if st.session_state["rtsp_started"] and st.session_state["last_url"] != url:
self.stop_stream()
if not st.session_state["rtsp_started"]:
cap = cv2.VideoCapture(url)
if not cap.isOpened():
st.error("Failed to open RTSP stream.")
return
st.session_state["cap"] = cap
st.session_state["last_url"] = url
st.session_state["rtsp_started"] = True
def stop_stream(self):
cap = st.session_state.get("cap")
if cap is not None:
cap.release()
st.session_state["cap"] = None
st.session_state["rtsp_started"] = False
st.session_state["last_url"] = ""
def loop(self):
box = st.empty()
try:
while st.session_state["rtsp_started"]:
cap: Optional[cv2.VideoCapture] = st.session_state.get("cap")
if cap is None:
break
ret, frame = cap.read()
if not ret:
break
# Memory keeps growing here
box.image(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB), channels="RGB")
time.sleep(0.03)
except Exception as e:
st.error(f"Loop error: {e}")
if __name__ == "__main__":
RTSPApp().run()
What I observe:
-
Memory grows at ~100 MB per minute.
-
Stopping the stream does not release memory.
-
With plain OpenCV (
cv2.imshow), memory stays stable.
Questions:
-
Is this a known issue with
st.image(maybe due to caching or history of frames)? -
Is there a way to explicitly free memory after calling
box.image(...)? -
Would a different approach (e.g.,
st.videowith MJPEG stream) be recommended to avoid leaks?
Thanks in advance for any insights or workarounds!