Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Turbo Streams + Flask] Memory leak when page is not in focus (Edge 103) #639

Open
danilofuchs opened this issue Jul 19, 2022 · 4 comments

Comments

@danilofuchs
Copy link

Issue Description

Webpage memory consumption is increasing over time, reaching over 3GB if the tab is not in focus, leading to a freeze with an out-of-memory error code.

If page goes back in focus or is refreshed, consumption is stable at 100MB.

Elements are being created and removed every 1 second, but it looks like old elements are not garbage collected when the tab is on background.

(readings from the chromium task manager)

Setup

Turbo-Flask 0.8.0 (Turbo 7.1.0)
Flask 2.1.2
Python 3.7.8
Microsoft Edge 103.0.1264.62

Use Case

Web page for monitoring a long running process.

Multiple variables update every 1 second, using turbo.update

turbo.push(turbo.update(
    render_template(
        'content_targets.html',
        targets=monitor.targets,
        metadata=monitor.metadata
     ),
     'targets'
    )
)

This recreates the entire web page every 1 second. On the dev tools, it is possible to see the DOM tree being updated.

Current workaround is to refresh the page every minute if in background:

setInterval(() => {
    if (document.hidden) {
        document.location.reload()
    }
}, 60 * 1000)
@tleish
Copy link
Contributor

tleish commented Jul 26, 2022

Can you share the contents of content_targets.html?

@danilofuchs
Copy link
Author

We have a list of 6 targets, updating every value every second.

There are 2 files updated every time. First is a summary card for the target being monitored:

content_targets.html
<div id="targets">
  <div class="row">

    {% for target in targets %}
      <!-- Target -->
      <div class="col-xl-3 col-md-6">
        <div class="card card-stats">
          <div class="card-body">
            <div class="row">
              <div class="col">
                <h5 class="card-title text-uppercase text-muted mb-0">
                  {{ target.name }} {{ target.ip }}:{{ target.port }}
                </h5>
                <span class="h2 font-weight-bold mb-0">{{ target.variant }}</span><br />
              </div>
              <div class="col-auto">
                {% if target.lastStatus == "Running" %}
                  <div class="icon icon-shape bg-gradient-green text-white rounded-circle shadow">
                    <i class="ni ni-chart-pie-35 gg-check"></i>
                  </div>
                {% else %}
                  <div class="icon icon-shape bg-gradient-red text-white rounded-circle shadow">
                    <i class="ni ni-chart-pie-35 gg-close"></i>
                  </div>
                {% endif %}
              </div>
            </div>
            <p class="mt-1 mb-0 text-sm">
              <span c lass="text-nowrap"></span>
              <span class="text-nowrap mr-2"><i class="fa fa-arrow-up"></i>{{ target.status }} {{ target.timestamp }}</span> <br />
              <span class="text-nowrap mr-2"><i class="fa fa-arrow-up"></i>SW Status: {{ target.lastStatus }}</span> <br />
              <span class="text-nowrap mr-2"><i class="fa fa-arrow-up"></i>{{ target.SWVersion }}</span> <br />
              <span class="text-nowrap mr-2"><i class="fa fa-arrow-up"></i>CPU: {{ target.CpuVersion }}</span> <br />
              <span class="text-nowrap mr-2"><i class="fa fa-arrow-up"></i>GPU: {{ target.GpuVersion }}</span>
            </p>
            <p class="mt-1 mb-0 text-sm">
              <span class="text-nowrap">Voltage output 1</span>
              <span class="text-success mr-2"><i class="fa fa-arrow-up"></i>{{ target.AvgVoltage1Monitoring }} V</span>
            </p>
            <p class="mt-1 mb-0 text-sm">
              <span class="text-nowrap">Current output 1</span>
              <span class="text-success mr-2"><i class="fa fa-arrow-up"></i>{{ target.AvgCurrent1Monitoring }} A</span>
            </p>
            <p class="mt-1 mb-0 text-sm">
              <span class="text-nowrap">Voltage output 2</span>
              <span class="text-success mr-2"><i class="fa fa-arrow-up"></i>{{ target.AvgVoltage2Monitoring }} V</span>
            </p>
            <p class="mt-1 mb-0 text-sm">
              <span class="text-nowrap">Current output 2</span>
              <span class="text-success mr-2"><i class="fa fa-arrow-up"></i>{{ target.AvgCurrent2Monitoring }} A</span>
            </p>
          </div>
        </div>
      </div> <!-- End of Target -->
    {% endfor %}

  </div> <!-- End of row -->
</div> <!-- End of main content -->

Second, there is a list of monitored values, composed of ~50 values for each target, totaling 300 distinct table rows:

monitoring.html
<div id="targets-monitoring">
  <div class="row">

    {% for target in targets %}
      <!-- Targets -->
      <div class="col-xl-2 col-md-6">
        <div class="card card-stats">
          <div class="card-body">
            <div class="row">
              <div class="col">
                <h5 class="card-title text-uppercase text-muted mb-0">
                  {{ target.name }} {{ target.ip }}:{{ target.port }}
                </h5>
                <span class="h2 font-weight-bold mb-0">{{ target.variant }}</span><br />
              </div>
              <div class="col-auto">
                {% if target.lastStatus == "Running" %}
                  <div class="icon icon-shape bg-gradient-green text-white rounded-circle shadow">
                    <i class="ni ni-chart-pie-35 gg-check"></i>
                  </div>
                {% else %}
                  <div class="icon icon-shape bg-gradient-red text-white rounded-circle shadow">
                    <i class="ni ni-chart-pie-35 gg-close"></i>
                  </div>
                {% endif %}
              </div>
            </div>
            <p class="mt-1 mb-0 text-sm">
              <span class="text-nowrap"></span>
              <span class="text-nowrap"><i class="fa fa-arrow-up"></i>{{ target.status }} {{ target.timestamp }}</span>
            </p>
            <p class="mt-1 mb-0">
              <span class="text-nowrap font-weight-bold" style="font-size: 14px;">Variable name</span>
              <span class="text-nowrap font-weight-bold" style="font-size: 14px; float:right;">Value</span>
            </p>
            <hr style="margin-top: 7px;margin-bottom: 7px;">
            {% for name in target.itemIdentifiers %}
              <p class="mt-1 mb-0">
                <span class="text-nowrap font-weight-normal" style="font-size: 12px;">{{ name }}</span>
                <span class="text-success font-weight-bold" style="font-size: 12px; float:right"><i class="fa fa-arrow-up"></i>{{ target.MonitoringItemsValue[loop.index0] }}</span>
              </p>
              <hr style="margin-top: 4px;margin-bottom: 4px;">
            {% endfor %}
          </div>
        </div>
      </div> <!-- End of Target -->
    {% endfor %}

  </div> <!-- End of row -->
</div> <!-- End of main content -->

@tleish
Copy link
Contributor

tleish commented Aug 11, 2022

I'm not sure if this is a turbo bug or a MS Edge bug. Does the same thing occur in other browsers? Are MS Edge "Sleeping Tabs" enabled or disabled? Does adjusting Sleeping Tabs settings fix the memory leak?

image

@danilofuchs
Copy link
Author

This does not occur on Firefox

Edge 104.0.1293.47 seems to have fixed the problem. Memory grows until ~500MB, than runs garbage collector and caps at 200MB

This is the same with or without Sleeping tabs.

We will run the test over a long period to make sure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants