Updating images in a while loop keeps increasing RAM, even after sessions are closed and cleaned up

Summary

Serving images at 10 FPS will keep increasing RAM. Even when the sessions are closed and stopped the RAM does only partially clean up. There is no upper bound, it keeps increasing over time. This will eventually lead to problems, especially on SBC with limited RAM. After running in multiple tabs, I am hitting 16GB RAM allready after about 10 minutes. Please not that having all sessions closed will not reduce RAM usage. It will stay steady at the last amount of RAM used, and after opening new sessions it will start climbing again.

Steps to reproduce

import datetime
import time

import cv2
import numpy as np
import streamlit as st

img = np.random.rand(600,600,3)

def get_image():
    # Get current date and time
    img_with_date = img.copy()
    now = datetime.datetime.now()
    dt_string = now.strftime("%d/%m/%Y %H:%M:%S.%f")[:-3]
    cv2.putText(img_with_date, dt_string, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2)
    return img_with_date

def app():
    if "page_open" not in st.session_state:
        st.session_state.page_open = True

    if "num_img" not in st.session_state:
        st.session_state.num_img = 0


    st.title("Test memory usage of st.image...")

    text_placeholder = st.empty()
    img_placeholder = st.empty()

    while "page_open" in st.session_state:
        text_placeholder.write(st.session_state.num_img)
        img_placeholder.image(get_image())

        st.session_state.num_img += 1
        time.sleep(1/10)

    print("Session ended...")
    img_placeholder.empty()
    text_placeholder.empty()
    st.stop()
if __name__ == "__main__":
    app()

Just run this app for a while, in multiple browser tabs will take up memory quicker. Then close them, stop the last app, clear the cache. then check the memory.

Expected behavior:

I donโ€™t know what the expected behavior would be from Streamltis perspective, but in my use case each image will ever be served once to each session. I want Streamlit to clean up these resources as soon as possible.

Actual behavior:

The behavior I am getting is that more and more RAM is being consumed over time. It does not increase anymore once all sessions are closed (using Streamlit 1.17.0 for that reason because 1.18+ keeps sessions open way longer than it should).

If you would run this code on Streamlit 1.18+ it would not terminate the sessions based on the session state condition, and it will lead to undesirable results.

Debug info

  • Streamlit version: 1.17.0
  • Python version: 3.10.9
  • Using Conda
  • OS version: Ubuntu 22.04 WSL2
  • Browser version: Google Chrome 110.0.5481.104

Requirements file

Only 2 packages needed:

pip install streamlit==1.17.0
pip install opencv-python-headless

That is understandable because you have an infinite loop in,

while "page_open" in st.session_state:
1 Like

Closing all sessions will keep the RAM usages approximately the same. Will update the post to better reflect that. If I let it climb up to 16 gigabytes of RAM usage and all sessions are closed it still uses 16 gigabytes of ram.

1 Like

@vdonato we discussed things on Github about the detection of closed sessions. Before I create an issue about this topic I want to ask if you see anything going wrong here? The sample I posted will just keep using more RAM (not when there are no sessions) but the RAM usage never goes down. Only stabilizes without open sessions but otherwise it keeps increasing.

So even when this issue gets resolved I am still not able to keep a single session open for longer than a few hours before I run out of memory. Are there some advanced settings to control image caching in RAM or am I just doing something wrong here?

1 Like

I tried your code but I am using windows 10. I also did not use conda. I created a virtual environment.

  • Run the app, I saw memory usage increase.
  • Duplicate tabs to increase memory usage rate. Total tabs is 4.
  • Close the 3 tabs.
  • Press the stop button for the last tab.
  • The memory usage was back to normal.

I have no memory issue with it.

1 Like

Hey @Mathijs,

Memory not being cleaned up for a single very-long-lived session isnโ€™t too surprising to me โ€“ I believe the refs to the images generated during a script run currently wonโ€™t be cleaned up until script execution has finished, so the garbage collector wonโ€™t reclaim the memory until after the script execution completes.

You could likely muck around with some Streamlit internals (in particular by calling methods defined in media_file_manager.py) to get this cleanup to happen more frequently. We canโ€™t guarantee the stability of the APIs of internal modules, but my unofficial opinion is that itโ€™s highly unlikely that MediaFileManagerโ€™s will change any time soon. Happy to help find a workaround using this method if I happen to have more time later this week, but I currently donโ€™t have too much bandwidth.

I am surprised that memory isnโ€™t being reclaimed even after a session ends, though. Please feel free to file a new GitHub issue for this and tag me in it if you have a consistent repro.

1 Like

Thanks for your reply. I created an issue on Github:

It was confirmed by @lukasmasuch (I hope his Github user matches his name in here :grinning: )

I will try to find a workaround. My idea for now is to find a way to delete images as soon as they are displayed, since they are only ever shown once in a session anyway.

1 Like

Hi, Iโ€™m also having memory issues updating pyplot charts.
Have you found any work around this?

1 Like